From dca68a7148d53a0c1ece96a9a9245ad2900672f8 Mon Sep 17 00:00:00 2001 From: nickmorales Date: Thu, 27 May 2021 11:12:35 -0400 Subject: [PATCH 01/14] fixes retrieval of genotyping plate layout --- lib/CXGN/Trial/TrialLayout/AbstractLayout.pm | 121 ++++++++++--------- lib/CXGN/Trial/TrialLayout/Analysis.pm | 8 +- lib/CXGN/Trial/TrialLayout/Genotyping.pm | 21 ++-- lib/CXGN/Trial/TrialLayout/Phenotyping.pm | 1 + lib/CXGN/Trial/TrialLayout/SamplingTrial.pm | 11 +- 5 files changed, 86 insertions(+), 76 deletions(-) diff --git a/lib/CXGN/Trial/TrialLayout/AbstractLayout.pm b/lib/CXGN/Trial/TrialLayout/AbstractLayout.pm index 0cf65e122b..629c504741 100644 --- a/lib/CXGN/Trial/TrialLayout/AbstractLayout.pm +++ b/lib/CXGN/Trial/TrialLayout/AbstractLayout.pm @@ -39,6 +39,10 @@ has 'source_stock_types' => (isa => 'ArrayRef[Str]', is=> 'rw', default =>sub { has 'source_stock_type_ids' => (isa => 'ArrayRef[Int]', is => 'rw' ); +has 'source_primary_stock_types' => (isa => 'ArrayRef[Str]', is=> 'rw', default =>sub { [ 'accession' ] }); + +has 'source_primary_stock_type_ids' => (isa => 'ArrayRef[Int]', is => 'rw' ); + has 'target_stock_types' => (isa => 'ArrayRef[Str]', is => 'rw', default => sub { [ 'plot' ] }); # the object things are placed on, such as plot has 'target_stock_type_ids' => (isa => 'ArrayRef[Int]', is => 'rw'); @@ -92,9 +96,9 @@ has 'cvterm_hash' => (isa => 'HashRef', is => 'rw'); sub BUILD { my $self = shift; my $args = shift; - + print STDERR "Build CXGN::Trial::TrialLayout::AbstractLayout... ($args->{trial_id})\n"; - + $self->_build_cvterm_hash(); } @@ -109,37 +113,44 @@ sub cvterm_id { sub convert_source_stock_types_to_ids { my $self = shift; - my @source_cvterm_ids; print STDERR "Converting source stock types to ids... \n"; - + + my @source_cvterm_ids; foreach my $source_stock (@{$self->get_source_stock_types()}) { - print STDERR "Converting $source_stock to ... "; - my $source_stock_cvterm_id = $self->cvterm_id($source_stock); - print STDERR "$source_stock_cvterm_id . \n"; - push @source_cvterm_ids, $source_stock_cvterm_id; + # print STDERR "Converting $source_stock to ... "; + my $source_stock_cvterm_id = $self->cvterm_id($source_stock); + # print STDERR "$source_stock_cvterm_id . \n"; + push @source_cvterm_ids, $source_stock_cvterm_id; } $self->set_source_stock_type_ids(\@source_cvterm_ids); + my @source_primary_cvterm_ids; + foreach my $source_stock (@{$self->get_source_primary_stock_types()}) { + # print STDERR "Converting $source_stock to ... "; + my $source_stock_cvterm_id = $self->cvterm_id($source_stock); + # print STDERR "$source_stock_cvterm_id . \n"; + push @source_primary_cvterm_ids, $source_stock_cvterm_id; + } + $self->set_source_primary_stock_type_ids(\@source_primary_cvterm_ids); + my @target_cvterm_ids; foreach my $target_stock (@{$self->get_target_stock_types()}) { - print STDERR "Converting $target_stock to ... "; - my $target_stock_cvterm_id = $self->cvterm_id($target_stock); - print STDERR "$target_stock_cvterm_id . \n"; - push @target_cvterm_ids, $target_stock_cvterm_id; + # print STDERR "Converting $target_stock to ... "; + my $target_stock_cvterm_id = $self->cvterm_id($target_stock); + # print STDERR "$target_stock_cvterm_id . \n"; + push @target_cvterm_ids, $target_stock_cvterm_id; } $self->set_target_stock_type_ids(\@target_cvterm_ids); - my @rel_type_cvterm_ids; foreach my $rel_type (@{$self->get_relationship_types()}) { - print STDERR "Converting $rel_type to ... "; - my $rel_type_cvterm_id = $self->cvterm_id($rel_type); - print STDERR "$rel_type_cvterm_id . \n"; - push @rel_type_cvterm_ids, $rel_type_cvterm_id; + # print STDERR "Converting $rel_type to ... "; + my $rel_type_cvterm_id = $self->cvterm_id($rel_type); + # print STDERR "$rel_type_cvterm_id . \n"; + push @rel_type_cvterm_ids, $rel_type_cvterm_id; } $self->set_relationship_type_ids(\@rel_type_cvterm_ids); - } @@ -174,7 +185,7 @@ sub _lookup_trial_id { my $design = $self->_set_design($self->_get_design_from_trial()); ### print STDERR "_lookup_trial_id TRIAL design is now ".Dumper($self->get_design()); - + $self->_set_plot_names($self->_get_plot_info_fields_from_trial("plot_name") || []); # moved to subclass $self->_set_block_numbers($self->_get_plot_info_fields_from_trial("block_number") || []); $self->_set_replicate_numbers($self->_get_plot_info_fields_from_trial("rep_number") || []); @@ -274,7 +285,7 @@ sub _get_plot_info_fields_from_trial { $unique_field_values{$design_info{$field_name}} = 1; } } - + if (! scalar(@field_values) >= 1){ return; } @@ -298,7 +309,7 @@ sub _get_design_from_trial { if (keys(%$design)) { print STDERR "WE HAVE TRIAL LAYOUT JSON!\n"; #print STDERR "TRIAL LAYOUT JSON IS: ".$trial_layout_json->value()."\n"; - + #Plant index number needs to be in the cached layout of trials that have plants. this serves a check to assure this. if ($trial_has_plants){ my @plot_values = values %$design; @@ -356,11 +367,11 @@ sub generate_and_cache_layout { # ->find({ 'type.name' => 'genotyping_project_name' }, {join => 'type' }); # $genotyping_project_name = $genotyping_project_name_row->get_column("value") || "unknown"; # } - + @plots = @{$plots_ref}; my %design; - + #print STDERR "PLOTS: ".Dumper(\@plots); foreach my $plot (@plots) { $self->retrieve_plot_info($plot, \%design); @@ -376,13 +387,13 @@ sub generate_and_cache_layout { $project->create_projectprops({ 'trial_layout_json' => encode_json(\%design) }); - + if ($self->get_verify_layout || $self->get_verify_physical_map){ return \%verify_errors; } #print STDERR "DESIGN AS READ : ".Dumper(\%design); - + return \%design; } @@ -394,9 +405,9 @@ sub retrieve_plot_info { #print STDERR "retrieve_plot_info()... Working on plot ".$plot->uniquename()."\n"; my %design_info; - + my $json = JSON->new(); - + # if ($self->get_experiment_type eq 'genotyping_trial'){ # $design_info{genotyping_user_id} = $genotyping_user_id; # #print STDERR "RETRIEVED: genotyping_user_id: $design{genotyping_user_id}\n"; @@ -427,15 +438,15 @@ sub retrieve_plot_info { my $well_notes_prop = $stockprop_hash{$self->cvterm_id('notes')} ? join ',', @{$stockprop_hash{$self->cvterm_id('notes')}} : undef; my $well_ncbi_taxonomy_id_prop = $stockprop_hash{$self->cvterm_id('ncbi_taxonomy_id')} ? join ',', @{$stockprop_hash{$self->cvterm_id('ncbi_taxonomy_id')}} : undef; my $plot_geo_json_prop = $stockprop_hash{$self->cvterm_id('plot_geo_json')} ? $stockprop_hash{$self->cvterm_id('plot_geo_json')}->[0] : undef; - + #print STDERR "SORUCE STOCK TYPES: ".Dumper($self->get_source_stock_type_ids())."\n".Dumper($self->get_source_stock_types()); #print STDERR "REL TYEPS = ".Dumper($self->get_relationship_types()); - + my $accession_rs = $plot->search_related('stock_relationship_subjects')->search( - { 'me.type_id' => { -in => $self->get_relationship_type_ids() }, 'object.type_id' => { -in => $self->get_source_stock_type_ids() } }, + { 'me.type_id' => { -in => $self->get_relationship_type_ids() }, 'object.type_id' => { -in => $self->get_source_primary_stock_type_ids() } }, { 'join' => 'object' } ); - + # was: $plot_of_cvterm_id, $tissue_sample_of_cvterm_id, $analysis_of_cvterm_id if ($accession_rs->count != 1){ die "There is more than one or no (".$accession_rs->count.") accession/cross/family_name linked here!\n"; @@ -481,31 +492,31 @@ sub retrieve_plot_info { # } my $accession = $accession_rs->first->object; my $plants = $plot->search_related('stock_relationship_subjects', { 'me.type_id' => $self->cvterm_id('plant_of')})->search_related('object', {'object.type_id' => $self->cvterm_id('plant') }, {order_by=>"object.stock_id"}); - + my $subplots = $plot->search_related('stock_relationship_subjects', { 'me.type_id' => $self->cvterm_id('subplot_of')})->search_related('object', {'object.type_id' => $self->cvterm_id('subplot')}, {order_by=>"object.stock_id"}); my $tissues = $plot->search_related('stock_relationship_objects', { 'me.type_id' => $self->cvterm_id('tissue_sample_of') })->search_related('subject', {'subject.type_id' => $self->cvterm_id('tissue_sample')}, {order_by=>"subject.stock_id"}); my $seedlot_transaction = $plot->search_related('stock_relationship_subjects', { 'me.type_id' => $self->cvterm_id('seed transaction'), 'object.type_id' => $self->cvterm_id('seedlot') }, {'join'=>'object', order_by=>"object.stock_id"}); if ($seedlot_transaction->count > 0 && $seedlot_transaction->count != 1){ die "There is more than one seedlot linked here!\n"; } - + my $accession_name = $accession->uniquename; my $accession_id = $accession->stock_id; - + $design_info{"plot_name"}=$plot_name; $design_info{"plot_id"}=$plot_id; my %unique_controls; my %unique_accessions; my %verify_errors; - + if ($plot_number_prop) { $design_info{"plot_number"}=$plot_number_prop; } else { die "no plot number stockprop found for plot $plot_name"; } - + if ($block_number_prop) { $design_info{"block_number"}=$block_number_prop; } @@ -584,7 +595,7 @@ sub retrieve_plot_info { push @{$verify_errors{errors}->{physical_map_errors}}, "Plot: $plot_name does not have a row_number and/or col_number!"; } } - + if ($seedlot_transaction->first()){ my $val = $json->decode($seedlot_transaction->first()->value()); my $seedlot = $seedlot_transaction->search_related('object'); @@ -616,19 +627,19 @@ sub retrieve_plot_info { my $plant_id = $p->stock_id(); push @plant_names, $plant_name; push @plant_ids, $plant_id; - + my $plant_number_rs = $p->search_related('stockprops', {'me.type_id' => $self->cvterm_id('plant_index_number') }); if ($plant_number_rs->count != 1){ print STDERR "Problem with plant_index_number stockprop for plant: $plant_name\n"; } my $plant_index_number = $plant_number_rs->first->value; push @plant_index_numbers, $plant_index_number; - + my $tissues_of_plant = $p->search_related('stock_relationship_objects', { 'me.type_id' => $self->cvterm_id('tissue_sample_of') })->search_related('subject', {'subject.type_id'=>$self->cvterm_id('tissue_sample')}); while (my $t = $tissues_of_plant->next()){ push @{$plants_tissue_hash{$plant_name}}, $t->uniquename(); } - + } $design_info{"plant_names"}=\@plant_names; $design_info{"plant_ids"}=\@plant_ids; @@ -650,7 +661,7 @@ sub retrieve_plot_info { my $tissue_id = $t->stock_id(); push @tissue_sample_names, $tissue_name; push @tissue_sample_ids, $tissue_id; - + my $tissue_number_rs = $t->search_related('stockprops', {'me.type_id' => $self->cvterm_id('tissue_sample_index_number') }); if ($tissue_number_rs->count > 0) { if ($tissue_number_rs->count != 1){ @@ -681,19 +692,19 @@ sub retrieve_plot_info { my $subplot_id = $p->stock_id(); push @subplot_names, $subplot_name; push @subplot_ids, $subplot_id; - + my $subplot_number_rs = $p->search_related('stockprops', {'me.type_id' => $self->cvterm_id('subplot_index_number') }); if ($subplot_number_rs->count != 1){ print STDERR "Problem with subplot_index_number stockprop for subplot: $subplot_name\n"; } my $subplot_index_number = $subplot_number_rs->first->value; push @subplot_index_numbers, $subplot_index_number; - + my $plants_of_subplot = $p->search_related('stock_relationship_objects', { 'me.type_id' => $self->cvterm_id('plant_of_subplot') })->search_related('subject', {'subject.type_id'=>$self->cvterm_id('plant')}); while (my $pp = $plants_of_subplot->next()){ push @{$subplots_plants_hash{$subplot_name}}, $pp->uniquename(); } - + my $tissues_of_subplot = $p->search_related('stock_relationship_objects', { 'me.type_id' => $self->cvterm_id('tissue_sample_of') })->search_related('subject', {'subject.type_id'=>$self->cvterm_id('tissue_sample')}); while (my $t = $tissues_of_subplot->next()){ push @{$subplots_tissues_hash{$subplot_name}}, $t->uniquename(); @@ -763,7 +774,7 @@ sub _get_design_type_from_project { my $design_prop; my $design_type; my $project; - + if (!$self->has_trial_id()) { print STDERR "Have no trial_id, aborting...\n"; return; @@ -792,7 +803,7 @@ sub _get_trial_year_from_project { my $project; my $year_prop; my $year; - + if (!$self->has_trial_id()) { return; } @@ -820,7 +831,7 @@ sub _get_plots { if (!$project) { return; } - + $field_layout_experiment = $self->_get_field_layout_experiment_from_project(); if (!$field_layout_experiment) { print STDERR "No field layout experiment found!\n"; @@ -831,7 +842,7 @@ sub _get_plots { my $source_cvterm_ids = $self->get_source_stock_type_ids(); print STDERR "EXP TYPE =".$self->get_experiment_type()."\n"; - + # if ($self->get_experiment_type eq 'field_layout'){ # $unit_type_id = $plot_cvterm_id; # } @@ -843,17 +854,17 @@ sub _get_plots { # $unit_type_id = $analysis_instance_cvterm_id; # } @plots = $field_layout_experiment->nd_experiment_stocks->search_related('stock', {'stock.type_id' => {-in => $self->get_target_stock_type_ids() } }); - + #debug... print STDERR "PLOT LIST: \n"; print STDERR join( "\n", map { $_->name() } @plots)."\n"; - + return \@plots; } sub _build_cvterm_hash { my $self = shift; - + print STDERR "Building cvterm has...\n"; my %hash; @@ -869,9 +880,9 @@ sub _build_cvterm_hash { $self->set_cvterm_hash(\%hash); } - - - + + + # $hash{accession} = SGN::Model::Cvterm->get_cvterm_row($self->get_schema(), "accession", "stock_type")->cvterm_id(); # $hash{cross} = SGN::Model::Cvterm->get_cvterm_row($self->get_schema(), "cross", "stock_type")->cvterm_id(); # $hash{family_name} = SGN::Model::Cvterm->get_cvterm_row($self->get_schema(), "family_name", "stock_type")->cvterm_id(); @@ -888,7 +899,7 @@ sub _build_cvterm_hash { # my $subplot_rel_cvterm_id = $subplot_rel_cvterm->cvterm_id(); # my $plant_rel_cvterm_id = $plant_rel_cvterm->cvterm_id(); # my $analysis_of_cvterm_id = $analysis_of_cv->cvterm_id(); - + # my $plant_of_subplot_rel_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($self->get_schema, 'plant_of_subplot', 'stock_relationship' )->cvterm_id(); # my $seed_transaction_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($self->get_schema, 'seed transaction', 'stock_relationship' )->cvterm_id(); diff --git a/lib/CXGN/Trial/TrialLayout/Analysis.pm b/lib/CXGN/Trial/TrialLayout/Analysis.pm index 9749f1bbf3..fd4cf51832 100644 --- a/lib/CXGN/Trial/TrialLayout/Analysis.pm +++ b/lib/CXGN/Trial/TrialLayout/Analysis.pm @@ -11,12 +11,13 @@ extends 'CXGN::Trial::TrialLayout::AbstractLayout'; sub BUILD { my $self = shift; + $self->set_source_primary_stock_types( [ "accession" ] ); $self->set_source_stock_types( [ "accession", "tissue_sample" ] ); $self->set_relationship_types( [ "analysis_of" ]); $self->set_target_stock_types( [ "analysis_instance" ]); $self->convert_source_stock_types_to_ids(); - + # probably better to lazy load the action design... # $self->_lookup_trial_id(); @@ -28,8 +29,3 @@ sub BUILD { __PACKAGE__->meta()->make_immutable(); 1; - - - - - diff --git a/lib/CXGN/Trial/TrialLayout/Genotyping.pm b/lib/CXGN/Trial/TrialLayout/Genotyping.pm index 667fcda0dc..0e1087d836 100644 --- a/lib/CXGN/Trial/TrialLayout/Genotyping.pm +++ b/lib/CXGN/Trial/TrialLayout/Genotyping.pm @@ -12,15 +12,16 @@ sub BUILD { my $self = shift; print STDERR "BUILD CXGN::Trial::TrialLayout::Genotyping...\n"; - - $self->set_source_stock_types( [ "accession" ] ); + + $self->set_source_primary_stock_types( [ "accession" ] ); + $self->set_source_stock_types( [ "accession", "plot", "plant", "tissue_sample", "subplot" ] ); $self->set_relationship_types( [ "tissue_sample_of" ] ); $self->set_target_stock_types( [ "tissue_sample" ] ); $self->convert_source_stock_types_to_ids(); - + # probably better to lazy load the action design... # - + $self->_lookup_trial_id(); } @@ -44,7 +45,7 @@ sub retrieve_plot_info { } if (! $plot_number) { print STDERR "NO PLOT NUMBER AVAILABLE!!!!\n"; } - + my $project = $self->get_project(); my $genotyping_user_id; my $genotyping_project_name; @@ -55,19 +56,19 @@ sub retrieve_plot_info { ->search_related("nd_experimentprops") ->find({ 'type.name' => 'genotyping_user_id' }, {join => 'type' }); $genotyping_user_id = $genotyping_user_id_row->get_column("value") || "unknown"; - + my $genotyping_project_name_row = $project ->search_related("nd_experiment_projects") ->search_related("nd_experiment") ->search_related("nd_experimentprops") ->find({ 'type.name' => 'genotyping_project_name' }, {join => 'type' }); $genotyping_project_name = $genotyping_project_name_row->get_column("value") || "unknown"; - + $design->{$plot_number}->{genotyping_user_id} = $genotyping_user_id; - print STDERR "RETRIEVED: genotyping_user_id: $design->{genotyping_user_id}\n"; + # print STDERR "RETRIEVED: genotyping_user_id: $design->{genotyping_user_id}\n"; $design->{$plot_number}->{genotyping_project_name} = $genotyping_project_name; - print STDERR "RETRIEVED: genotyping_project_name: $design->{genotyping_project_name}\n"; - + # print STDERR "RETRIEVED: genotyping_project_name: $design->{genotyping_project_name}\n"; + my $source_rs = $plot->search_related('stock_relationship_subjects')->search( { 'me.type_id' => { -in => $self->get_relationship_type_ids() }, 'object.type_id' => { -in => $self->get_source_stock_type_ids() } }, { 'join' => 'object' } diff --git a/lib/CXGN/Trial/TrialLayout/Phenotyping.pm b/lib/CXGN/Trial/TrialLayout/Phenotyping.pm index 7ba4540f87..242e9ac59f 100644 --- a/lib/CXGN/Trial/TrialLayout/Phenotyping.pm +++ b/lib/CXGN/Trial/TrialLayout/Phenotyping.pm @@ -13,6 +13,7 @@ sub BUILD { my $self = shift; print STDERR "BUILD CXGN::Trial::TrialLayout::Phenotyping...\n"; + $self->set_source_primary_stock_types( [ "accession", "cross", "family_name" ] ); $self->set_source_stock_types([ 'accession', 'cross', 'family_name', 'subplot', 'plant', 'grafted_accession' ] ); $self->set_relationship_types([ 'plot_of', 'member_of', 'plant_of_subplot', 'tissue_sample_of']); $self->set_target_stock_types( [ 'plot'] ); diff --git a/lib/CXGN/Trial/TrialLayout/SamplingTrial.pm b/lib/CXGN/Trial/TrialLayout/SamplingTrial.pm index ca865a1013..b3ff7f27c0 100644 --- a/lib/CXGN/Trial/TrialLayout/SamplingTrial.pm +++ b/lib/CXGN/Trial/TrialLayout/SamplingTrial.pm @@ -12,15 +12,16 @@ sub BUILD { my $self = shift; print STDERR "BUILD CXGN::Trial::TrialLayout::SamplingTrial...\n"; - + + $self->set_source_primary_stock_types( [ "accession" ] ); $self->set_source_stock_types( [ "accession" ] ); $self->set_relationship_types( [ "tissue_sample_of" ] ); $self->set_target_stock_types( [ "tissue_sample" ] ); $self->convert_source_stock_types_to_ids(); - + # probably better to lazy load the action design... # - + $self->_lookup_trial_id(); } @@ -44,9 +45,9 @@ sub retrieve_plot_info { } if (! $plot_number) { print STDERR "NO PLOT NUMBER AVAILABLE!!!!\n"; } - + my $project = $self->get_project(); - + my $source_rs = $plot->search_related('stock_relationship_subjects')->search( { 'me.type_id' => { -in => $self->get_relationship_type_ids() }, 'object.type_id' => { -in => $self->get_source_stock_type_ids() } }, { 'join' => 'object' } From 684e37ee36497d95bc3543cc636a5c4d5e4f38f6 Mon Sep 17 00:00:00 2001 From: Chris T Date: Fri, 28 May 2021 10:22:46 -0400 Subject: [PATCH 02/14] changes to POST/PUT studies to not require location and allow for any study type. --- db/00139/AddMiscellaneousTrialType.pm | 85 ++++++++ lib/CXGN/BrAPI/v2/ObservationUnits.pm | 2 +- lib/CXGN/BrAPI/v2/Studies.pm | 268 ++++++++++++++++++-------- lib/CXGN/Project.pm | 63 +++--- lib/CXGN/Trial/Folder.pm | 68 +++---- lib/CXGN/Trial/Search.pm | 9 +- lib/CXGN/Trial/TrialCreate.pm | 13 +- 7 files changed, 350 insertions(+), 158 deletions(-) create mode 100644 db/00139/AddMiscellaneousTrialType.pm diff --git a/db/00139/AddMiscellaneousTrialType.pm b/db/00139/AddMiscellaneousTrialType.pm new file mode 100644 index 0000000000..fc20683d86 --- /dev/null +++ b/db/00139/AddMiscellaneousTrialType.pm @@ -0,0 +1,85 @@ +#!/usr/bin/env perl + + +=head1 NAME + + AddMiscellaneousTrialType + +=head1 SYNOPSIS + +mx-run ThisPackageName [options] -H hostname -D dbname -u username [-F] + +this is a subclass of L +see the perldoc of parent class for more details. + +=head1 DESCRIPTION + +This patch add a sytem cvterm that is used to store miscellaneous trial types for trials. + +This subclass uses L. The parent class uses L + +=head1 AUTHOR + + Chris Tucker + +=head1 COPYRIGHT & LICENSE + +Copyright 2010 Boyce Thompson Institute for Plant Research + +This program is free software; you can redistribute it and/or modify +it under the same terms as Perl itself. + +=cut + + +package AddMiscellaneousTrialType; + +use Moose; +use Try::Tiny; +use Bio::Chado::Schema; + +extends 'CXGN::Metadata::Dbpatch'; + + +has '+description' => ( default => <<'' ); +This patch add a sytem cvterm that is used to store miscellaneous trial types for trials. + +has '+prereq' => ( + default => sub { + [], + }, +); + +sub patch { + my $self=shift; + + print STDOUT "Executing the patch:\n " . $self->name . ".\n\nDescription:\n ". $self->description . ".\n\nExecuted by:\n " . $self->username . " ."; + print STDOUT "\nChecking if this db_patch was executed before or if previous db_patches have been executed.\n"; + print STDOUT "\nExecuting the SQL commands.\n"; + + + my $coderef = sub { + + my $schema = Bio::Chado::Schema->connect( sub { $self->dbh->clone } ); + + my $new_cvterm = $schema->resultset("Cv::Cvterm")->create_with( + { + name => 'misc_trial', + definition => 'A trial type that holds any trial type', + cv => 'project_type', + }); + }; + + try { + $schema->txn_do($coderef); + + } catch { + die "Load failed! " . $_ . "\n" ; + }; + + print "You're done!\n"; +} + +#### +1; # +#### diff --git a/lib/CXGN/BrAPI/v2/ObservationUnits.pm b/lib/CXGN/BrAPI/v2/ObservationUnits.pm index 8b75f985c9..47224b3801 100644 --- a/lib/CXGN/BrAPI/v2/ObservationUnits.pm +++ b/lib/CXGN/BrAPI/v2/ObservationUnits.pm @@ -594,7 +594,7 @@ sub observationunits_store { my $project = $self->bcs_schema->resultset("Project::Project")->find( { project_id => $trial_id }); my $design_prop = $project->projectprops->find( { 'type.name' => 'design' },{ join => 'type'}); #there should be only one design prop. if (!$design_prop) { - return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Study doe not have a proper Study type.')); + return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Study does not have a proper Study type.')); } my $design_type = $design_prop->value; diff --git a/lib/CXGN/BrAPI/v2/Studies.pm b/lib/CXGN/BrAPI/v2/Studies.pm index 767b6d8680..2d9e6d139b 100644 --- a/lib/CXGN/BrAPI/v2/Studies.pm +++ b/lib/CXGN/BrAPI/v2/Studies.pm @@ -148,9 +148,28 @@ sub detail { my %additional_info = (); my $project_type = ''; - if ($t->get_project_type()) { - $project_type = $t->get_project_type()->[1]; + my $project_type_array = $t->get_project_type(); + if ($project_type_array) { + my $project_type_name = $project_type_array->[1]; + my $misc_type_cvterm = SGN::Model::Cvterm->get_cvterm_row($self->bcs_schema(), 'misc_trial', 'project_type'); + printf($misc_type_cvterm->name()); + printf($project_type_name); + if ($project_type_name eq $misc_type_cvterm->name()) { + my $rs = $self->bcs_schema()->resultset('Project::Projectprop')->search( + { + type_id => $misc_type_cvterm->cvterm_id(), + project_id => $t->get_trial_id() + }); + if ($rs->count() > 0) { + $project_type = $rs->first()->value(); + } + } + + if (! defined $project_type){ + $project_type = $project_type_name; + } } + my $location_id = ''; my $location_name = ''; if ($t->get_location()) { @@ -287,12 +306,6 @@ sub store { my $page = $self->page; my $status = $self->status; - my @project_type_ids = CXGN::Trial::get_all_project_types($self->bcs_schema()); - my %project_type_ids; - foreach (@project_type_ids) { - $project_type_ids{$_->[1]} = $_->[0]; - } - my @study_dbids; foreach my $params (@{$data}) { @@ -303,33 +316,58 @@ sub store { my $trial_design_method = $params->{experimentalDesign} ? $params->{experimentalDesign}->{PUI} : undef; #Design type must be either: genotyping_plate, CRD, Alpha, Augmented, Lattice, RCBD, MAD, p-rep, greenhouse, or splitplot; my $folder_id = $params->{trialDbId} ? $params->{trialDbId} : undef; my $study_type = $params->{studyType} ? $params->{studyType} : undef; - my $trial_type = $project_type_ids{$study_type}; my $field_size = $params->{additionalInfo}->{field_size} ? $params->{additionalInfo}->{field_size} : undef; my $plot_width = $params->{additionalInfo}->{plot_width} ? $params->{additionalInfo}->{plot_width} : undef; my $plot_length = $params->{additionalInfo}->{plot_length} ? $params->{additionalInfo}->{plot_length} : undef; - if(!$trial_type){ - return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Study type name: ' . $study_type . ' does not exist. Check study types supported!')); - } - my $folder = CXGN::Trial::Folder->new(bcs_schema=>$self->bcs_schema(), folder_id=>$folder_id); - - my $program; - if($folder->breeding_program){ - $program = $folder->breeding_program->name(); - } elsif ($folder->name()){ - $program = $folder->name(); + if (!$folder_id) { + return CXGN::BrAPI::JSONResponse->return_error($self->status, 'trialDbId is required', 400); + } + if(!$study_type){ + return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Study type is required'), 400); } + # Check the trial exists + my $brapi_trial = $self->bcs_schema()->resultset('Project::Project')->find( { project_id=>$folder_id }); + if (! defined $brapi_trial) { + return CXGN::BrAPI::JSONResponse->return_error($self->status, 'Trial does not exist with that id', 404); + } + + my $folder = CXGN::Trial::Folder->new(bcs_schema=>$self->bcs_schema(), folder_id=>$folder_id); + my $program; + if($folder->breeding_program){ + $program = $folder->breeding_program->name(); + } elsif ($folder->name()){ + $program = $folder->name(); + } + my $save; my $coderef = sub { + # Use the misc_trial type if it doesn't match any of the other ones. + my @project_type_ids = CXGN::Trial::get_all_project_types($self->bcs_schema()); + my %project_type_ids; + foreach (@project_type_ids) { + $project_type_ids{$_->[1]} = $_->[0]; + } + + my $trial_type; + if ($project_type_ids{$study_type}) { + $trial_type = $project_type_ids{$study_type}; + } else { + # Create a new trial type + my $misc_type_cvterm = SGN::Model::Cvterm->get_cvterm_row($self->bcs_schema(), 'misc_trial', 'project_type'); + $trial_type = $misc_type_cvterm->cvterm_id(); + } + my %trial_info_hash = ( chado_schema => $schema, dbh => $dbh, trial_year => $trial_year, - trial_description => $trial_description, + trial_description => $trial_description || '', trial_location => $trial_location, trial_type => $trial_type, + trial_type_value => $study_type, trial_name => $trial_name, user_name => $user_name, #not implemented design_type => $trial_design_method, @@ -357,7 +395,7 @@ sub store { my $error = $save->{error}; if ($error){ $schema->txn_rollback(); - return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('There was an error storing studies. %s', $error)); + return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('There was an error storing studies. %s', $error, 500)); } return $save->{project_id}; }; @@ -365,10 +403,10 @@ sub store { #save data eval { my $trial_id = $schema->txn_do($coderef); - if (ref \$trial_id eq 'SCALAR'){ push @study_dbids, $trial_id; + # Associate the study with the trial my $folder = CXGN::Trial::Folder->new( { bcs_schema => $schema, @@ -378,6 +416,10 @@ sub store { $folder->associate_parent($folder_id); } }; + if ($@) { + warn $@; + return CXGN::BrAPI::JSONResponse->return_error($self->status, 'There was an error saving the study', 500); + }; } my $data_out; @@ -400,6 +442,7 @@ sub store { } sub update { + #TODO: This needs to update to the object sent. Currently it only changes fields that are sent my $self = shift; my $params = shift; my $user_id =shift; @@ -434,13 +477,6 @@ sub update { print STDERR "my user roles = @user_roles and trial breeding program = $breeding_program_name \n"; - #Get project type - my @project_type_ids = CXGN::Trial::get_all_project_types($self->bcs_schema()); - my %project_type_ids; - foreach (@project_type_ids) { - $project_type_ids{$_->[1]} = $_->[0]; - } - # set each new detail that is defined my $study_name = $params->{studyName} ? $params->{studyName} : undef; my $study_description = $params->{studyDescription} ? $params->{studyDescription} : undef; @@ -449,20 +485,49 @@ sub update { my $study_design_method = $params->{experimentalDesign} ? $params->{experimentalDesign}->{PUI} : undef; #Design type must be either: genotyping_plate, CRD, Alpha, Augmented, Lattice, RCBD, MAD, p-rep, greenhouse, or splitplot; my $folder_id = $params->{trialDbId} ? $params->{trialDbId} : undef; my $study_t = $params->{studyType} ? $params->{studyType} : undef; - my $study_type = $project_type_ids{$study_t}; my $field_size = $params->{additionalInfo}->{field_size} ? $params->{additionalInfo}->{field_size} : undef; my $plot_width = $params->{additionalInfo}->{plot_width} ? $params->{additionalInfo}->{plot_width} : undef; my $plot_length = $params->{additionalInfo}->{plot_length} ? $params->{additionalInfo}->{plot_length} : undef; my $planting_date = $params->{startDate} ? $params->{startDate} : undef; my $harvest_date = $params->{endDate} ? $params->{endDate} : undef; - if(!$study_type && $study_t){ - return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Study type name: ' . $study_t . ' does not exist. Check study types supported!')); + if (!$folder_id) { + return CXGN::BrAPI::JSONResponse->return_error($self->status, 'trialDbId is required', 400); + } + if(!$study_t){ + return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Study type is required'), 400); } + + # Check the brapi trial exists + my $brapi_trial = $self->bcs_schema()->resultset('Project::Project')->find( { project_id=>$folder_id }); + if (! defined $brapi_trial) { + return CXGN::BrAPI::JSONResponse->return_error($self->status, 'Trial does not exist with that id', 404); + } + + # Get the trial (brapi trial) parent my $folder = CXGN::Trial::Folder->new(bcs_schema=>$self->bcs_schema(), folder_id=>$folder_id); + printf(Dumper($folder)); + # Get the breeding program for that brapi trial my $program = $folder->breeding_program->project_id(); # eval { + + # Use the misc_trial type if it doesn't match any of the other ones. + my @project_type_ids = CXGN::Trial::get_all_project_types($self->bcs_schema()); + my %project_type_ids; + foreach (@project_type_ids) { + $project_type_ids{$_->[1]} = $_->[0]; + } + + my $trial_type; + if ($project_type_ids{$study_t}) { + $trial_type = $project_type_ids{$study_t}; + } else { + # Create a new trial type + my $misc_type_cvterm = SGN::Model::Cvterm->get_cvterm_row($self->bcs_schema(), 'misc_trial', 'project_type'); + $trial_type = $misc_type_cvterm->cvterm_id(); + } + my $trial_name_exists = CXGN::Trial::Search->new({ bcs_schema => $schema, metadata_schema => $metadata_schema, @@ -470,16 +535,23 @@ sub update { trial_name_list => [$study_name] }); my ($data, $total_count) = $trial_name_exists->search(); - - if($total_count>0){ - return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf("Can't create trial: Trial name already exists\n")); + + # Check that the object found was not the object we are trying to update + my $non_object_match = 0; + foreach (@$data){ + if ($_->{trial_id} ne $trial_id) { + $non_object_match = 1; + } + } + if($total_count>0 && $non_object_match eq 1){ + return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf("Can't create trial: Trial name already exists\n"), 409); } my $trial = CXGN::Trial->new({ bcs_schema => $schema, metadata_schema => $metadata_schema, phenome_schema => $phenome_schema, trial_id => $trial_id - }); + }); if ($study_name) { $trial->set_name($study_name); } if ($folder_id) { $trial->set_breeding_program($program); @@ -491,7 +563,7 @@ sub update { } if ($study_location) { $trial->set_location($study_location); } if ($study_year) { $trial->set_year($study_year); } - if ($study_type) { $trial->set_project_type($study_type); } + if ($trial_type) { $trial->set_project_type($trial_type, $study_t); } if ($planting_date) { if ($planting_date eq '') { $trial->remove_planting_date($trial->get_planting_date()); } else { $trial->set_planting_date($planting_date); } @@ -656,37 +728,38 @@ sub _search { description => $t->get_design_type() }; } - my $folder_id = $t->get_folder()->id(); - my $folder_name = $t->get_folder()->name(); + my $folder_id = $t->get_folder()->id(); + my $folder_name = $t->get_folder()->name(); + my $trial_type = $_->{trial_type} ne 'misc_trial' ? $_->{trial_type} : $_->{trial_type_value}; my %data_obj = ( - active=>JSON::true, - additionalInfo=>\%additional_info, - commonCropName => $supported_crop, - contacts => $brapi_contacts, - culturalPractices => undef, - dataLinks => \@data_links, - documentationURL => "", - endDate => $harvest_date ? $harvest_date : undef , - environmentParameters => undef, - experimentalDesign => $experimental_design, - externalReferences => undef, - growthFacility => undef, - lastUpdate => undef, - license => $data_agreement, - locationDbId => $_->{location_id}, - locationName => $_->{location_name}, - observationLevels => undef, + active => JSON::true, + additionalInfo => \%additional_info, + commonCropName => $supported_crop, + contacts => $brapi_contacts, + culturalPractices => undef, + dataLinks => \@data_links, + documentationURL => "", + endDate => $harvest_date ? $harvest_date : undef, + environmentParameters => undef, + experimentalDesign => $experimental_design, + externalReferences => undef, + growthFacility => undef, + lastUpdate => undef, + license => $data_agreement, + locationDbId => $_->{location_id}, + locationName => $_->{location_name}, + observationLevels => undef, observationUnitsDescription => undef, - seasons => \@seasons, - startDate => $planting_date ? $planting_date : undef, - studyCode => qq|$_->{trial_id}|, - studyDbId => qq|$_->{trial_id}|, - studyDescription => $_->{description}, - studyName => $_->{trial_name}, - studyPUI => undef, - studyType => $_->{trial_type}, - trialDbId => qq|$folder_id|, - trialName => $folder_name + seasons => \@seasons, + startDate => $planting_date ? $planting_date : undef, + studyCode => qq|$_->{trial_id}|, + studyDbId => qq|$_->{trial_id}|, + studyDescription => $_->{description}, + studyName => $_->{trial_name}, + studyPUI => undef, + studyType => $trial_type, + trialDbId => qq|$folder_id|, + trialName => $folder_name ); push @data_out, \%data_obj; } @@ -714,15 +787,6 @@ sub _save_trial { return { error => "Trial not saved: breeding program does not exist" }; } - my $geolocation; - my $geolocation_lookup = CXGN::Location::LocationLookup->new(schema => $chado_schema); - $geolocation_lookup->set_location_name($self->get_trial_location()); - $geolocation = $geolocation_lookup->get_geolocation(); - if (!$geolocation) { - print STDERR "Can't create trial: Location not found\n"; - return { error => "Trial not saved: location not found" }; - } - my $project_year_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'project year', 'project_property'); my $project_design_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'design', 'project_property'); my $field_size_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'field_size', 'project_property'); @@ -734,33 +798,66 @@ sub _save_trial { my $has_subplot_entries_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'project_has_subplot_entries', 'project_property'); my $trial_stock_type_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'trial_stock_type', 'project_property'); + # Create the trial (brapi study) my $project = $chado_schema->resultset('Project::Project') ->create({ name => $trial_name, description => $self->get_trial_description(), }); + # Gets the trial (brapi study) my $t = CXGN::Project->new({ bcs_schema => $chado_schema, trial_id => $project->project_id() }); print STDERR "TRIAL TYPE = ".ref($t)."!!!!\n"; - my $nd_experiment_type_id = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'field_layout', 'experiment_type')->cvterm_id(); + # Check if a location was passed, set as N/A location if it does not exist + my $geolocation; + if (defined $self->get_trial_location()) { + my $geolocation_lookup = CXGN::Location::LocationLookup->new(schema => $chado_schema); + $geolocation_lookup->set_location_name($self->get_trial_location()); + $geolocation = $geolocation_lookup->get_geolocation(); + } else { + # Check if there is already a N/A location + my $na_location_name = 'N/A'; + my $geolocation_lookup = CXGN::Location::LocationLookup->new(schema => $chado_schema); + $geolocation_lookup->set_location_name($na_location_name); + $geolocation = $geolocation_lookup->get_geolocation(); + + if (! defined $geolocation){ + # Create a N/A location + $geolocation = CXGN::Location->new( { + bcs_schema => $chado_schema, + name => $na_location_name + }); + my $store = $geolocation->store_location(); + if (defined $store->{error}) { + return $store; + } else { + $geolocation->nd_geolocation_id($store->{nd_geolocation_id}); + } + } + } + + my $nd_experiment_type_id = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'field_layout', 'experiment_type')->cvterm_id(); my $nd_experiment = $chado_schema->resultset('NaturalDiversity::NdExperiment') ->create({ nd_geolocation_id => $geolocation->nd_geolocation_id(), type_id => $nd_experiment_type_id, }); + #link location to the trial (brapi study) + $nd_experiment->find_or_create_related('nd_experiment_projects',{project_id => $project->project_id()}); my $source_field_trial_ids = $t->set_field_trials_source_field_trials($self->get_field_trial_from_field_trial); $t->set_location($geolocation->nd_geolocation_id()); # set location also as a project prop $t->set_breeding_program($self->get_breeding_program_id); if ($self->get_trial_type){ - $t->set_project_type($self->get_trial_type); + $t->set_project_type($self->get_trial_type, $self->get_trial_type_value); } + if ($self->get_planting_date){ $t->set_planting_date($self->get_planting_date); } @@ -768,13 +865,16 @@ sub _save_trial { $t->set_harvest_date($self->get_harvest_date); } - #link to the project - $nd_experiment->find_or_create_related('nd_experiment_projects',{project_id => $project->project_id()}); - - $project->create_projectprops({ - $project_year_cvterm->name() => $self->get_trial_year(), - $project_design_cvterm->name() => $self->get_design_type() - }); + if ($self->has_trial_year) { + $project->create_projectprops({ + $project_year_cvterm->name() => $self->get_trial_year() + }); + } + if ($self->has_design_type) { + $project->create_projectprops({ + $project_design_cvterm->name() => $self->get_design_type() + }); + } if ($self->has_field_size && $self->get_field_size){ $project->create_projectprops({ $field_size_cvterm->name() => $self->get_field_size diff --git a/lib/CXGN/Project.pm b/lib/CXGN/Project.pm index d2740b471f..03c40962e0 100644 --- a/lib/CXGN/Project.pm +++ b/lib/CXGN/Project.pm @@ -102,42 +102,42 @@ sub BUILD { print STDERR "BUILD CXGN::Project... with ".$args->{trial_id}."\n"; if (! $args->{description}) { - $args->{description} = "(No description provided)"; + $args->{description} = "(No description provided)"; } my $row = $self->bcs_schema()->resultset("Project::Project")->find( { project_id => $args->{trial_id} }); # print STDERR "PROJECT ID = $args->{trial_id}\n"; if ($row){ - $self->name( $row->name() ); + $self->name( $row->name() ); } if ($args->{trial_id} && ! $row) { - die "The trial ".$args->{trial_id}." does not exist - aborting."; + die "The trial ".$args->{trial_id}." does not exist - aborting."; } $row = $self->bcs_schema()->resultset("Project::Project")->find( { name => $args->{name } } ); if (! $args->{trial_id} && $row) { - die "A trial with the name $args->{name} already exists. Please choose another name."; + die "A trial with the name $args->{name} already exists. Please choose another name."; } if (! $args->{trial_id} && ! $row) { - print STDERR "INSERTING A NEW ROW...\n"; + print STDERR "INSERTING A NEW ROW...\n"; my $new_row = $args->{bcs_schema}->resultset("Project::Project")->create( { name => $args->{name}, description => $args->{description} }); - my $project_id = $new_row->project_id(); - print STDERR "new project object has project id $project_id\n"; + my $project_id = $new_row->project_id(); + print STDERR "new project object has project id $project_id\n"; - $self->set_trial_id($project_id); + $self->set_trial_id($project_id); } if ($args->{trial_id} && $row) { - # print STDERR "Existing project... populating object.\n"; - $self->set_trial_id($args->{trial_id}); - $self->name($args->{name}); - $self->description($args->{description}); + # print STDERR "Existing project... populating object.\n"; + $self->set_trial_id($args->{trial_id}); + $self->name($args->{name}); + $self->description($args->{description}); } } @@ -925,30 +925,35 @@ sub get_project_type { sub set_project_type { my $self = shift; my $type_id = shift; - my $project_id = $self->get_trial_id(); - my @project_type_ids = CXGN::Trial::get_all_project_types($self->bcs_schema()); - my $type; + my $type_value = shift; + my $project_id = $self->get_trial_id(); + my @project_type_ids = CXGN::Trial::get_all_project_types($self->bcs_schema()); + my $type; - foreach my $pt (@project_type_ids) { - if ($pt->[0] eq $type_id) { - $type = $pt->[1]; - } + foreach my $pt (@project_type_ids) { + if ($pt->[0] eq $type_id) { + $type = $pt->[1]; + } } - my @ids = map { $_->[0] } @project_type_ids; + if ($type eq 'misc_trial' && defined $type_value) { + $type = $type_value; + } + + my @ids = map { $_->[0] } @project_type_ids; my $rs = $self->bcs_schema()->resultset('Project::Projectprop')->search({ - type_id => { -in => [ @ids ] }, - project_id => $project_id - }); + type_id => { -in => [ @ids ] }, + project_id => $project_id + }); if (my $row = $rs->next()) { - $row->delete(); + $row->delete(); } - my $row = $self->bcs_schema()->resultset('Project::Projectprop')->create({ - project_id => $project_id, - type_id => $type_id, - value => $type, - }); + my $row = $self->bcs_schema()->resultset('Project::Projectprop')->create({ + project_id => $project_id, + type_id => $type_id, + value => $type, + }); } diff --git a/lib/CXGN/Trial/Folder.pm b/lib/CXGN/Trial/Folder.pm index e2566c54d3..6a7128795d 100644 --- a/lib/CXGN/Trial/Folder.pm +++ b/lib/CXGN/Trial/Folder.pm @@ -390,51 +390,51 @@ sub set_folder_content_type { sub associate_parent { my $self = shift; - my $parent_id = shift; + my $parent_id = shift; - my $folder_cvterm_id = $self->folder_cvterm_id(); - my $breeding_program_trial_relationship_id = $self->breeding_program_trial_relationship_id(); + my $folder_cvterm_id = $self->folder_cvterm_id(); + my $breeding_program_trial_relationship_id = $self->breeding_program_trial_relationship_id(); - #If the user selects 'None' to remove the trial from the folder, then the parent_id will be passed as 0. No new parent will be created. - if ($parent_id == 0) { - $self->remove_parents; - return; - } + #If the user selects 'None' to remove the trial from the folder, then the parent_id will be passed as 0. No new parent will be created. + if ($parent_id == 0) { + $self->remove_parents; + return; + } - my $parent_row = $self->bcs_schema()->resultset("Project::Project")->find( { project_id => $parent_id } ); + my $parent_row = $self->bcs_schema()->resultset("Project::Project")->find( { project_id => $parent_id } ); - if (!$parent_row) { - print STDERR "The folder specified as parent does not exist"; - return; - } + if (!$parent_row) { + print STDERR "The folder specified as parent does not exist"; + return; + } - my $parentprop_row = $self->bcs_schema()->resultset("Project::Projectprop")->find( { project_id => $parent_id, type_id => { -in => [ $folder_cvterm_id, $breeding_program_trial_relationship_id ] } } ); + my $parentprop_row = $self->bcs_schema()->resultset("Project::Projectprop")->find( { project_id => $parent_id, type_id => { -in => [ $folder_cvterm_id, $breeding_program_trial_relationship_id ] } } ); - if (!$parentprop_row) { - print STDERR "The specified parent folder is not of type folder or breeding program. Ignoring."; - return; - } + if (!$parentprop_row) { + print STDERR "The specified parent folder is not of type folder or breeding program. Ignoring."; + return; + } - $self->remove_parents; + $self->remove_parents; - my $project_rel_row = $self->bcs_schema()->resultset('Project::ProjectRelationship')->create({ - object_project_id => $parent_id, - subject_project_id => $self->folder_id(), - type_id => $folder_cvterm_id, - }); - $project_rel_row->insert(); + my $project_rel_row = $self->bcs_schema()->resultset('Project::ProjectRelationship')->create({ + object_project_id => $parent_id, + subject_project_id => $self->folder_id(), + type_id => $folder_cvterm_id, + }); + $project_rel_row->insert(); $self->project_parent($parent_row); - my $parent_is_child = check_if_folder_is_child_in_tree($self->bcs_schema, $parent_id, $self->children()); - if ($parent_is_child) { - print STDERR 'Parent '.$parent_id.' is child in tree of folder '.$self->folder_id()."\n"; - my $parent_folder = CXGN::Trial::Folder->new({ - bcs_schema => $self->bcs_schema, - folder_id => $parent_id - }); - $parent_folder->remove_parents; - } + my $parent_is_child = check_if_folder_is_child_in_tree($self->bcs_schema, $parent_id, $self->children()); + if ($parent_is_child) { + print STDERR 'Parent '.$parent_id.' is child in tree of folder '.$self->folder_id()."\n"; + my $parent_folder = CXGN::Trial::Folder->new({ + bcs_schema => $self->bcs_schema, + folder_id => $parent_id + }); + $parent_folder->remove_parents; + } } diff --git a/lib/CXGN/Trial/Search.pm b/lib/CXGN/Trial/Search.pm index c500580b35..749ca76f63 100644 --- a/lib/CXGN/Trial/Search.pm +++ b/lib/CXGN/Trial/Search.pm @@ -247,7 +247,7 @@ sub search { if ($trial_type_list && scalar(@$trial_type_list)>0) { my $sql = join ("','" , @$trial_type_list); my $trial_type_sql = "'" . $sql . "'"; - push @where_clause, "trial_type_name.name in ($trial_type_sql)"; + push @where_clause, "(trial_type_name.name in ($trial_type_sql) OR projectprop.value in ($trial_type_sql))"; } if ($trial_id_list && scalar(@$trial_id_list)>0) { my $sql = join ("," , @$trial_id_list); @@ -311,7 +311,7 @@ sub search { my $where_clause = scalar(@where_clause)>0 ? " WHERE " . (join (" AND " , @where_clause)) : ''; - my $q = "SELECT study.name, study.project_id, study.description, folder.name, folder.project_id, folder.description, trial_type_name.cvterm_id, trial_type_name.name, year.value, location.value, breeding_program.name, breeding_program.project_id, breeding_program.description, harvest_date.value, planting_date.value, design.value, genotyping_facility.value, genotyping_facility_submitted.value, genotyping_facility_status.value, genotyping_plate_format.value, genotyping_plate_sample_type.value, genotyping_facility_plate_id.value, sampling_facility.value, sampling_facility_sample_type.value, count(study.project_id) OVER() AS full_count + my $q = "SELECT study.name, study.project_id, study.description, folder.name, folder.project_id, folder.description, trial_type_name.cvterm_id, trial_type_name.name, projectprop.value as trial_type_value, year.value, location.value, breeding_program.name, breeding_program.project_id, breeding_program.description, harvest_date.value, planting_date.value, design.value, genotyping_facility.value, genotyping_facility_submitted.value, genotyping_facility_status.value, genotyping_plate_format.value, genotyping_plate_sample_type.value, genotyping_facility_plate_id.value, sampling_facility.value, sampling_facility_sample_type.value, count(study.project_id) OVER() AS full_count FROM project AS study JOIN project_relationship AS bp_rel ON(study.project_id=bp_rel.subject_project_id AND bp_rel.type_id=$breeding_program_trial_relationship_id) JOIN project AS breeding_program ON(bp_rel.object_project_id=breeding_program.project_id) @@ -337,7 +337,7 @@ sub search { $accession_join $trait_join $where_clause - GROUP BY(study.name, study.project_id, study.description, folder.name, folder.project_id, folder.description, trial_type_name.cvterm_id, trial_type_name.name, year.value, location.value, breeding_program.name, breeding_program.project_id, breeding_program.description, harvest_date.value, planting_date.value, design.value, genotyping_facility.value, genotyping_facility_submitted.value, genotyping_facility_status.value, genotyping_plate_format.value, genotyping_plate_sample_type.value, genotyping_facility_plate_id.value, sampling_facility.value, sampling_facility_sample_type.value) + GROUP BY(study.name, study.project_id, study.description, folder.name, folder.project_id, folder.description, trial_type_name.cvterm_id, trial_type_name.name, projectprop.value, year.value, location.value, breeding_program.name, breeding_program.project_id, breeding_program.description, harvest_date.value, planting_date.value, design.value, genotyping_facility.value, genotyping_facility_submitted.value, genotyping_facility_status.value, genotyping_plate_format.value, genotyping_plate_sample_type.value, genotyping_facility_plate_id.value, sampling_facility.value, sampling_facility_sample_type.value) ORDER BY study.name;"; print STDERR Dumper $q; @@ -347,7 +347,7 @@ sub search { my @result; my $total_count = 0; my $subtract_count = 0; - while (my ($study_name, $study_id, $study_description, $folder_name, $folder_id, $folder_description, $trial_type_id, $trial_type_name, $year, $location_id, $breeding_program_name, $breeding_program_id, $breeding_program_description, $harvest_date, $planting_date, $design, $genotyping_facility, $genotyping_facility_submitted, $genotyping_facility_status, $genotyping_plate_format, $genotyping_plate_sample_type, $genotyping_facility_plate_id, $sampling_facility, $sampling_facility_sample_type, $full_count) = $h->fetchrow_array()) { + while (my ($study_name, $study_id, $study_description, $folder_name, $folder_id, $folder_description, $trial_type_id, $trial_type_name, $trial_type_value, $year, $location_id, $breeding_program_name, $breeding_program_id, $breeding_program_description, $harvest_date, $planting_date, $design, $genotyping_facility, $genotyping_facility_submitted, $genotyping_facility_status, $genotyping_plate_format, $genotyping_plate_sample_type, $genotyping_facility_plate_id, $sampling_facility, $sampling_facility_sample_type, $full_count) = $h->fetchrow_array()) { my $location_name = $location_id ? $locations{$location_id} : ''; my $project_harvest_date = $harvest_date ? $calendar_funcs->display_start_date($harvest_date) : ''; my $project_planting_date = $planting_date ? $calendar_funcs->display_start_date($planting_date) : ''; @@ -378,6 +378,7 @@ sub search { trial_type => $trial_type_name, trial_type_name => $trial_type_name, trial_type_id => $trial_type_id, + trial_type_value => $trial_type_value, year => $year, location_id => $location_id, location_name => $location_name, diff --git a/lib/CXGN/Trial/TrialCreate.pm b/lib/CXGN/Trial/TrialCreate.pm index 4e0fa50b9e..2ee5ed2f2e 100644 --- a/lib/CXGN/Trial/TrialCreate.pm +++ b/lib/CXGN/Trial/TrialCreate.pm @@ -146,13 +146,14 @@ has 'dbh' => (is => 'rw',predicate => 'has_dbh', required => 1,); #has 'user_name' => (isa => 'Str', is => 'rw', predicate => 'has_user_name', required => 1,); has 'trial_id' => (isa => 'Maybe[Int]', is => 'rw', predicate => 'has_trial_id'); has 'program' => (isa =>'Str', is => 'rw', predicate => 'has_program', required => 1,); -has 'trial_year' => (isa => 'Str', is => 'rw', predicate => 'has_trial_year', required => 1,); -has 'trial_description' => (isa => 'Str', is => 'rw', predicate => 'has_trial_description', required => 1,); -has 'trial_location' => (isa => 'Str', is => 'rw', predicate => 'has_trial_location', required => 1,); -has 'design_type' => (isa => 'Str', is => 'rw', predicate => 'has_design_type', required => 1); -has 'design' => (isa => 'HashRef[HashRef]|Undef', is => 'rw', predicate => 'has_design', required => 1); +has 'trial_year' => (isa => 'Maybe[Str]', is => 'rw', predicate => 'has_trial_year', required => 0,); +has 'trial_description' => (isa => 'Maybe[Str]', is => 'rw', predicate => 'has_trial_description', required => 0,); +has 'trial_location' => (isa => 'Maybe[Str]', is => 'rw', predicate => 'has_trial_location', required => 0,); +has 'design_type' => (isa => 'Maybe[Str]', is => 'rw', predicate => 'has_design_type', required => 0); +has 'design' => (isa => 'HashRef[HashRef]|Undef', is => 'rw', predicate => 'has_design', required => 0); has 'trial_name' => (isa => 'Str', is => 'rw', predicate => 'has_trial_name', required => 1); -has 'trial_type' => (isa => 'Str', is => 'rw', predicate => 'has_trial_type', required => 0); +has 'trial_type' => (isa => 'Str', is => 'rw', predicate => 'has_trial_type', required => 1); +has 'trial_type_value' => (isa => 'Str', is => 'rw', predicate => 'has_trial_type', required => 0); has 'trial_has_plant_entries' => (isa => 'Int', is => 'rw', predicate => 'has_trial_has_plant_entries', required => 0); has 'trial_has_subplot_entries' => (isa => 'Int', is => 'rw', predicate => 'has_trial_has_subplot_entries', required => 0); has 'field_size' => (isa => 'Num', is => 'rw', predicate => 'has_field_size', required => 0); From ac1f0c66ae9083cefff6c07a9321f52c2328c201 Mon Sep 17 00:00:00 2001 From: Chris T Date: Fri, 28 May 2021 10:23:17 -0400 Subject: [PATCH 03/14] add generic json type check and required fields check to brapi endpoints --- lib/CXGN/BrAPI/v2/Studies.pm | 14 ---------- lib/SGN/Controller/AJAX/BrAPI.pm | 46 +++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/lib/CXGN/BrAPI/v2/Studies.pm b/lib/CXGN/BrAPI/v2/Studies.pm index 2d9e6d139b..b51158a999 100644 --- a/lib/CXGN/BrAPI/v2/Studies.pm +++ b/lib/CXGN/BrAPI/v2/Studies.pm @@ -320,13 +320,6 @@ sub store { my $plot_width = $params->{additionalInfo}->{plot_width} ? $params->{additionalInfo}->{plot_width} : undef; my $plot_length = $params->{additionalInfo}->{plot_length} ? $params->{additionalInfo}->{plot_length} : undef; - if (!$folder_id) { - return CXGN::BrAPI::JSONResponse->return_error($self->status, 'trialDbId is required', 400); - } - if(!$study_type){ - return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Study type is required'), 400); - } - # Check the trial exists my $brapi_trial = $self->bcs_schema()->resultset('Project::Project')->find( { project_id=>$folder_id }); if (! defined $brapi_trial) { @@ -491,13 +484,6 @@ sub update { my $planting_date = $params->{startDate} ? $params->{startDate} : undef; my $harvest_date = $params->{endDate} ? $params->{endDate} : undef; - if (!$folder_id) { - return CXGN::BrAPI::JSONResponse->return_error($self->status, 'trialDbId is required', 400); - } - if(!$study_t){ - return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Study type is required'), 400); - } - # Check the brapi trial exists my $brapi_trial = $self->bcs_schema()->resultset('Project::Project')->find( { project_id=>$folder_id }); if (! defined $brapi_trial) { diff --git a/lib/SGN/Controller/AJAX/BrAPI.pm b/lib/SGN/Controller/AJAX/BrAPI.pm index d01ae911f7..f3b8c7ae46 100644 --- a/lib/SGN/Controller/AJAX/BrAPI.pm +++ b/lib/SGN/Controller/AJAX/BrAPI.pm @@ -136,8 +136,18 @@ sub brapi : Chained('/') PathPart('brapi') CaptureArgs(1) { $c->stash->{session_token} = $session_token; if (defined $c->request->data){ - if ($c->request->method ne "PUT"){ + if ($c->request->method eq "POST"){ + if (ref $c->request->data ne 'ARRAY') { + my $response = CXGN::BrAPI::JSONResponse->return_error($c->stash->{status}, 'Array data type required', 400); + _standard_response_construction($c, $response); + } $c->stash->{clean_inputs} = _clean_inputs($c->req->params,$c->request->data); + } elsif ($c->request->method eq "PUT") { + if (ref $c->request->data eq 'ARRAY') { + my $response = CXGN::BrAPI::JSONResponse->return_error($c->stash->{status}, 'Hash data type required', 400); + _standard_response_construction($c, $response); + } + $c->stash->{clean_inputs} = $c->request->data; } else { $c->stash->{clean_inputs} = $c->request->data; } @@ -185,6 +195,36 @@ sub _clean_inputs { return $params; } +sub _validate_request { + my $c = shift; + my $data_type = shift; + my $data = shift; + my $required_fields = shift; + + # Check the required fields + # TODO: Only top level right now, maybe in the future add nested checks + if ($required_fields) { + if ($data_type eq 'ARRAY') { + foreach my $object (values %{$data}) { + foreach my $required_field (@{$required_fields}) { + print $required_field; + if (!$object->{$required_field}) { + my $response = CXGN::BrAPI::JSONResponse->return_error($c->stash->{status}, sprintf('%s required', $required_field), 400); + _standard_response_construction($c, $response); + } + } + } + } elsif ($data_type eq 'HASH') { + foreach my $required_field (@{$required_fields}) { + if (!$data->{$required_field}) { + my $response = CXGN::BrAPI::JSONResponse->return_error($c->stash->{status}, sprintf('%s required', $required_field), 400); + _standard_response_construction($c, $response); + } + } + } + } +} + sub _authenticate_user { my $c = shift; my $force_authenticate = shift; @@ -1997,6 +2037,8 @@ sub studies_POST { my ($auth, $user_id) = _authenticate_user($c); my $clean_inputs = $c->stash->{clean_inputs}; my $data = $clean_inputs; + _validate_request($c, 'ARRAY', $data, ['trialDbId', 'studyName', 'studyType']); + my @all_studies; foreach my $study (values %{$data}) { push @all_studies, $study; @@ -2140,7 +2182,9 @@ sub studies_info_PUT { my ($auth,$user_id) = _authenticate_user($c); my $clean_inputs = $c->stash->{clean_inputs}; my $data = $clean_inputs; + _validate_request($c, 'HASH', $data, ['trialDbId', 'studyName', 'studyType']); $data->{studyDbId} = $c->stash->{study_id}; + my $brapi = $self->brapi_module; my $brapi_module = $brapi->brapi_wrapper('Studies'); my $brapi_package_result = $brapi_module->update($data,$user_id,$c); From 5885c96e9a396ee94936681df75f28faea72871e Mon Sep 17 00:00:00 2001 From: Chris T Date: Fri, 28 May 2021 10:24:11 -0400 Subject: [PATCH 04/14] add additional info to brapi studies --- lib/CXGN/BrAPI/v2/Studies.pm | 228 ++++++++++------------------------ lib/CXGN/Project.pm | 27 ++++ lib/CXGN/Trial/Search.pm | 62 ++++----- lib/CXGN/Trial/TrialCreate.pm | 1 + 4 files changed, 127 insertions(+), 191 deletions(-) diff --git a/lib/CXGN/BrAPI/v2/Studies.pm b/lib/CXGN/BrAPI/v2/Studies.pm index b51158a999..8de933f638 100644 --- a/lib/CXGN/BrAPI/v2/Studies.pm +++ b/lib/CXGN/BrAPI/v2/Studies.pm @@ -135,156 +135,16 @@ sub detail { my $page = $self->page; my $status = $self->status; - my $total_count = 0; - my %result; - my $study_check = $self->bcs_schema->resultset('Project::Project')->find({project_id=>$study_id}); - if ($study_check) { - my $t = CXGN::Trial->new({ bcs_schema => $self->bcs_schema, trial_id => $study_id }); - $total_count = 1; - my $folder = CXGN::Trial::Folder->new( { folder_id => $study_id, bcs_schema => $self->bcs_schema } ); - if ($folder->folder_type eq 'trial') { - - my @season = ($t->get_year()); - - my %additional_info = (); - my $project_type = ''; - my $project_type_array = $t->get_project_type(); - if ($project_type_array) { - my $project_type_name = $project_type_array->[1]; - my $misc_type_cvterm = SGN::Model::Cvterm->get_cvterm_row($self->bcs_schema(), 'misc_trial', 'project_type'); - printf($misc_type_cvterm->name()); - printf($project_type_name); - if ($project_type_name eq $misc_type_cvterm->name()) { - my $rs = $self->bcs_schema()->resultset('Project::Projectprop')->search( - { - type_id => $misc_type_cvterm->cvterm_id(), - project_id => $t->get_trial_id() - }); - if ($rs->count() > 0) { - $project_type = $rs->first()->value(); - } - } - - if (! defined $project_type){ - $project_type = $project_type_name; - } - } + my ($data_out,$total_count) = _search($self,$self->bcs_schema(),$page_size,$page,$supported_crop,[$study_id]); - my $location_id = ''; - my $location_name = ''; - if ($t->get_location()) { - $location_id = $t->get_location()->[0]; - $location_name = $t->get_location()->[1]; - } - my $planting_date; - if ($t->get_planting_date()) { - $planting_date = $t->get_planting_date(); - my $t = Time::Piece->strptime($planting_date, "%Y-%B-%d"); - $planting_date = $t->strftime("%Y-%m-%d"); - if($planting_date == "") { $planting_date = undef; } - } - my $harvest_date; - if ($t->get_harvest_date()) { - $harvest_date = $t->get_harvest_date(); - my $t = Time::Piece->strptime($harvest_date, "%Y-%B-%d"); - $harvest_date = $t->strftime("%Y-%m-%d"); - if($harvest_date == "") { $harvest_date = undef;} - } - my $contacts = $t->get_trial_contacts(); - my $brapi_contacts; - foreach (@$contacts){ - push @$brapi_contacts, { - contactDbId => $_->{sp_person_id}, - name => $_->{salutation}." ".$_->{first_name}." ".$_->{last_name}, - instituteName => $_->{organization}, - email => $_->{email}, - type => $_->{user_type}, - orcid => '' - }; - } - my $location = CXGN::Trial::get_all_locations($self->bcs_schema, $location_id)->[0]; - - my $additional_files = $t->get_additional_uploaded_files(); - my @data_links; - foreach (@$additional_files){ - push @data_links, { - scientificType => 'Additional File', - name => $_->[4], - url => $main_production_site_url.'/breeders/phenotyping/download/'.$_->[0], - provenance => undef, - dataFormat => undef, - description => undef, - fileFormat => undef, - version => undef - }; - } - - # my $phenotype_files = $t->get_phenotype_metadata(); - # foreach (@$phenotype_files){ - # push @data_links, { - # scientificType => 'Uploaded Phenotype File', - # name => $_->[4], - # url => $main_production_site_url.'/breeders/phenotyping/download/'.$_->[0], - # provenance => undef, - # dataFormat => undef, - # description => undef, - # fileFormat => undef, - # version => undef - # }; - # } - - my $data_agreement = $t->get_data_agreement() ? $t->get_data_agreement() : ''; - my $study_db_id = $t->get_trial_id(); - my $folder_db_id = $folder->project_parent->project_id(); - my $breeding_program_id = $folder->breeding_program->project_id(); - - my $experimental_design = {}; - - if ($t->get_design_type()){ - $experimental_design = { PUI => undef, - description => $t->get_design_type(), - }; - } - - %result = ( - active=>JSON::true, - additionalInfo=>\%additional_info, - commonCropName => $supported_crop, - contacts => $brapi_contacts, - culturalPractices => undef, - dataLinks =>\@data_links, - documentationURL => "", - endDate => $harvest_date ? $harvest_date : undef , - environmentParameters => undef, - experimentalDesign => $experimental_design, - externalReferences => undef, - growthFacility => undef, - lastUpdate => undef, - license => $data_agreement, - locationDbId => $location_id, - locationName => $location_name, - observationLevels => undef, - observationUnitsDescription => undef, - seasons => \@season, - startDate => $planting_date ? $planting_date : undef, - studyDbId=>qq|$study_db_id|, - studyDescription=>$t->get_description(), - studyName=>$t->get_name(), - studyType=>$project_type, - trialDbId=>qq|$folder_db_id|, - trialName=>$folder->project_parent->name(), - studyCode => qq|$study_db_id|, - studyPUI => undef, - ); - } else { - return CXGN::BrAPI::JSONResponse->return_error($status, 'StudyDbId not a study'); - } + if ($data_out > 0){ + my $result = @$data_out[0]; + my @data_files; + my $pagination = CXGN::BrAPI::Pagination->pagination_response($total_count,$page_size,$page); + return CXGN::BrAPI::JSONResponse->return_success($result, $pagination, \@data_files, $status, 'Studies search result constructed'); } else { - return CXGN::BrAPI::JSONResponse->return_error($status, 'StudyDbId not found'); + return CXGN::BrAPI::JSONResponse->return_error($status, 'StudyDbId not found', 404); } - my @data_files; - my $pagination = CXGN::BrAPI::Pagination->pagination_response($total_count,$page_size,$page); - return CXGN::BrAPI::JSONResponse->return_success(\%result, $pagination, \@data_files, $status, 'Studies detail result constructed'); } sub store { @@ -319,6 +179,16 @@ sub store { my $field_size = $params->{additionalInfo}->{field_size} ? $params->{additionalInfo}->{field_size} : undef; my $plot_width = $params->{additionalInfo}->{plot_width} ? $params->{additionalInfo}->{plot_width} : undef; my $plot_length = $params->{additionalInfo}->{plot_length} ? $params->{additionalInfo}->{plot_length} : undef; + my $raw_additional_info = $params->{additionalInfo} || undef; + my %specific_keys = map { $_ => 1 } ("field_size", "plot_width", "plot_length"); + my %additional_info; + if (defined $raw_additional_info) { + foreach my $key (keys %$raw_additional_info) { + if (!exists($specific_keys{$key})) { + $additional_info{$key} = $raw_additional_info->{$key}; + } + } + } # Check the trial exists my $brapi_trial = $self->bcs_schema()->resultset('Project::Project')->find( { project_id=>$folder_id }); @@ -334,6 +204,20 @@ sub store { $program = $folder->name(); } + # Check that a study with this name does not already exist + my $metadata_schema = $self->metadata_schema; + my $phenome_schema = $self->phenome_schema; + my $trial_name_exists = CXGN::Trial::Search->new({ + bcs_schema => $schema, + metadata_schema => $metadata_schema, + phenome_schema => $phenome_schema, + trial_name_list => [$trial_name] + }); + my ($data, $total_count) = $trial_name_exists->search(); + if ($total_count > 0) { + return CXGN::BrAPI::JSONResponse->return_error($self->status, sprintf('Study with the name \'%s\' already exists', $trial_name), 409); + } + my $save; my $coderef = sub { @@ -368,7 +252,8 @@ sub store { program => $program, # upload_trial_file => $upload, operator => $user_name, - trial_stock_type => 'accession' #can be cross or family name, not implemented + trial_stock_type => 'accession', #can be cross or family name, not implemented + additional_info => \%additional_info ); print STDERR "Trial type is ".$trial_info_hash{'trial_type'}."\n"; @@ -481,6 +366,16 @@ sub update { my $field_size = $params->{additionalInfo}->{field_size} ? $params->{additionalInfo}->{field_size} : undef; my $plot_width = $params->{additionalInfo}->{plot_width} ? $params->{additionalInfo}->{plot_width} : undef; my $plot_length = $params->{additionalInfo}->{plot_length} ? $params->{additionalInfo}->{plot_length} : undef; + my $raw_additional_info = $params->{additionalInfo} || undef; + my %specific_keys = map { $_ => 1 } ("field_size", "plot_width", "plot_length"); + my %additional_info; + if (defined $raw_additional_info) { + foreach my $key (keys %$raw_additional_info) { + if (!exists($specific_keys{$key})) { + $additional_info{$key} = $raw_additional_info->{$key}; + } + } + } my $planting_date = $params->{startDate} ? $params->{startDate} : undef; my $harvest_date = $params->{endDate} ? $params->{endDate} : undef; @@ -492,7 +387,6 @@ sub update { # Get the trial (brapi trial) parent my $folder = CXGN::Trial::Folder->new(bcs_schema=>$self->bcs_schema(), folder_id=>$folder_id); - printf(Dumper($folder)); # Get the breeding program for that brapi trial my $program = $folder->breeding_program->project_id(); @@ -563,21 +457,17 @@ sub update { if ($plot_width) { $trial->set_plot_width($plot_width); } if ($plot_length) { $trial->set_plot_length($plot_length); } if ($study_design_method) { $trial->set_design_type($study_design_method); } + if (%additional_info) { $trial->set_additional_info(\%additional_info); } # }; - my $data_out; - my $total_count=0; - my $supported_crop = $c->config->{"supportedCrop"}; - ($data_out,$total_count) = _search($self,$schema,$page_size,$page,$supported_crop,[$trial_id]); - - my %result = (data=>$data_out); + my ($data_out,$total_count) = _search($self,$self->bcs_schema(),$page_size,$page,$supported_crop,[$trial_id]); + my $result = @$data_out[0]; my @data_files; my $pagination = CXGN::BrAPI::Pagination->pagination_response($total_count,$page_size,$page); - return CXGN::BrAPI::JSONResponse->return_success(\%result, $pagination, \@data_files, $status, 'Studies result constructed'); - + return CXGN::BrAPI::JSONResponse->return_success($result, $pagination, \@data_files, $status, 'Studies result constructed'); } sub format_date { @@ -647,10 +537,18 @@ sub _search { my @data_out; foreach (@$data){ - my %additional_info = ( - programDbId => qq|$_->{breeding_program_id}|, + my $additional_info = { + programDbId => qq|$_->{breeding_program_id}|, programName => $_->{breeding_program_name}, - ); + }; + # Join the additional info with the existing additional info + if ($_->{additional_info}) { + print Dumper($_->{additional_info}); + foreach my $key (keys %{$_->{additional_info}}){ + $additional_info->{$key} = $_->{additional_info}->{$key}; + } + } + my @seasons = ( $_->{"year"} ); my $planting_date; @@ -719,7 +617,7 @@ sub _search { my $trial_type = $_->{trial_type} ne 'misc_trial' ? $_->{trial_type} : $_->{trial_type_value}; my %data_obj = ( active => JSON::true, - additionalInfo => \%additional_info, + additionalInfo => $additional_info, commonCropName => $supported_crop, contacts => $brapi_contacts, culturalPractices => undef, @@ -738,7 +636,7 @@ sub _search { observationUnitsDescription => undef, seasons => \@seasons, startDate => $planting_date ? $planting_date : undef, - studyCode => qq|$_->{trial_id}|, + studyCode => undef, studyDbId => qq|$_->{trial_id}|, studyDescription => $_->{description}, studyName => $_->{trial_name}, @@ -783,6 +681,7 @@ sub _save_trial { my $has_plant_entries_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'project_has_plant_entries', 'project_property'); my $has_subplot_entries_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'project_has_subplot_entries', 'project_property'); my $trial_stock_type_cvterm = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'trial_stock_type', 'project_property'); + my $additional_info_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($chado_schema,'project_additional_info', 'project_property'); # Create the trial (brapi study) my $project = $chado_schema->resultset('Project::Project') @@ -881,6 +780,11 @@ sub _save_trial { $trial_stock_type_cvterm->name() => $self->get_trial_stock_type }); } + if ($self->get_additional_info) { + $project->create_projectprops({ + $additional_info_cvterm_id->name() => encode_json($self->get_additional_info) + }); + } return { project_id => $project->project_id() }; } diff --git a/lib/CXGN/Project.pm b/lib/CXGN/Project.pm index 03c40962e0..6d3c453001 100644 --- a/lib/CXGN/Project.pm +++ b/lib/CXGN/Project.pm @@ -95,6 +95,11 @@ has 'year' => ( lazy => 1, ); +has 'additional_info' => ( + is => 'rw', + isa => 'Maybe[HashRef]' +); + sub BUILD { my $self = shift; my $args = shift; @@ -1847,6 +1852,28 @@ sub set_field_size { $self->_set_projectprop('field_size', $value); } +=head2 accessors get_additional_info(), set_additional_info() + + Usage: For field trials, this stores brapi additional information + Desc: + Ret: + Args: + Side Effects: + Example: + +=cut + +sub get_additional_info { + my $self = shift; + my $additional_info = $self->_get_projectprop('project_additional_info'); + return $additional_info ? decode_json($additional_info) : undef; +} + +sub set_additional_info { + my $self = shift; + my $value = shift; + $self->_set_projectprop('project_additional_info', encode_json($value)); +} sub _get_projectprop { my $self = shift; diff --git a/lib/CXGN/Trial/Search.pm b/lib/CXGN/Trial/Search.pm index 749ca76f63..6e2240947e 100644 --- a/lib/CXGN/Trial/Search.pm +++ b/lib/CXGN/Trial/Search.pm @@ -35,6 +35,7 @@ use Try::Tiny; use Data::Dumper; use SGN::Model::Cvterm; use CXGN::Calendar; +use JSON; has 'bcs_schema' => ( isa => 'Bio::Chado::Schema', is => 'rw', @@ -194,6 +195,7 @@ sub search { my $genotyping_facility_plate_id_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'genotyping_facility_plate_id', 'project_property')->cvterm_id(); my $sampling_facility_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'sampling_facility', 'project_property')->cvterm_id(); my $sampling_facility_sample_type_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($schema, 'sampling_trial_sample_type', 'project_property')->cvterm_id(); + my $additional_info_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($self->bcs_schema,'project_additional_info', 'project_property')->cvterm_id(); my $calendar_funcs = CXGN::Calendar->new({}); @@ -311,7 +313,7 @@ sub search { my $where_clause = scalar(@where_clause)>0 ? " WHERE " . (join (" AND " , @where_clause)) : ''; - my $q = "SELECT study.name, study.project_id, study.description, folder.name, folder.project_id, folder.description, trial_type_name.cvterm_id, trial_type_name.name, projectprop.value as trial_type_value, year.value, location.value, breeding_program.name, breeding_program.project_id, breeding_program.description, harvest_date.value, planting_date.value, design.value, genotyping_facility.value, genotyping_facility_submitted.value, genotyping_facility_status.value, genotyping_plate_format.value, genotyping_plate_sample_type.value, genotyping_facility_plate_id.value, sampling_facility.value, sampling_facility_sample_type.value, count(study.project_id) OVER() AS full_count + my $q = "SELECT study.name, study.project_id, study.description, folder.name, folder.project_id, folder.description, trial_type_name.cvterm_id, trial_type_name.name, projectprop.value as trial_type_value, year.value, location.value, breeding_program.name, breeding_program.project_id, breeding_program.description, harvest_date.value, planting_date.value, design.value, genotyping_facility.value, genotyping_facility_submitted.value, genotyping_facility_status.value, genotyping_plate_format.value, genotyping_plate_sample_type.value, genotyping_facility_plate_id.value, sampling_facility.value, sampling_facility_sample_type.value, project_additional_info.value, count(study.project_id) OVER() AS full_count FROM project AS study JOIN project_relationship AS bp_rel ON(study.project_id=bp_rel.subject_project_id AND bp_rel.type_id=$breeding_program_trial_relationship_id) JOIN project AS breeding_program ON(bp_rel.object_project_id=breeding_program.project_id) @@ -334,10 +336,11 @@ sub search { LEFT JOIN projectprop AS genotyping_facility_plate_id ON(study.project_id=genotyping_facility_plate_id.project_id AND genotyping_facility_plate_id.type_id=$genotyping_facility_plate_id_cvterm_id) LEFT JOIN projectprop AS sampling_facility ON(study.project_id=sampling_facility.project_id AND sampling_facility.type_id=$sampling_facility_cvterm_id) LEFT JOIN projectprop AS sampling_facility_sample_type ON(study.project_id=sampling_facility_sample_type.project_id AND sampling_facility_sample_type.type_id=$sampling_facility_sample_type_cvterm_id) + LEFT JOIN projectprop AS project_additional_info ON(study.project_id=project_additional_info.project_id AND project_additional_info.type_id=$additional_info_cvterm_id) $accession_join $trait_join $where_clause - GROUP BY(study.name, study.project_id, study.description, folder.name, folder.project_id, folder.description, trial_type_name.cvterm_id, trial_type_name.name, projectprop.value, year.value, location.value, breeding_program.name, breeding_program.project_id, breeding_program.description, harvest_date.value, planting_date.value, design.value, genotyping_facility.value, genotyping_facility_submitted.value, genotyping_facility_status.value, genotyping_plate_format.value, genotyping_plate_sample_type.value, genotyping_facility_plate_id.value, sampling_facility.value, sampling_facility_sample_type.value) + GROUP BY(study.name, study.project_id, study.description, folder.name, folder.project_id, folder.description, trial_type_name.cvterm_id, trial_type_name.name, projectprop.value, year.value, location.value, breeding_program.name, breeding_program.project_id, breeding_program.description, harvest_date.value, planting_date.value, design.value, genotyping_facility.value, genotyping_facility_submitted.value, genotyping_facility_status.value, genotyping_plate_format.value, genotyping_plate_sample_type.value, genotyping_facility_plate_id.value, sampling_facility.value, sampling_facility_sample_type.value, project_additional_info.value) ORDER BY study.name;"; print STDERR Dumper $q; @@ -347,7 +350,7 @@ sub search { my @result; my $total_count = 0; my $subtract_count = 0; - while (my ($study_name, $study_id, $study_description, $folder_name, $folder_id, $folder_description, $trial_type_id, $trial_type_name, $trial_type_value, $year, $location_id, $breeding_program_name, $breeding_program_id, $breeding_program_description, $harvest_date, $planting_date, $design, $genotyping_facility, $genotyping_facility_submitted, $genotyping_facility_status, $genotyping_plate_format, $genotyping_plate_sample_type, $genotyping_facility_plate_id, $sampling_facility, $sampling_facility_sample_type, $full_count) = $h->fetchrow_array()) { + while (my ($study_name, $study_id, $study_description, $folder_name, $folder_id, $folder_description, $trial_type_id, $trial_type_name, $trial_type_value, $year, $location_id, $breeding_program_name, $breeding_program_id, $breeding_program_description, $harvest_date, $planting_date, $design, $genotyping_facility, $genotyping_facility_submitted, $genotyping_facility_status, $genotyping_plate_format, $genotyping_plate_sample_type, $genotyping_facility_plate_id, $sampling_facility, $sampling_facility_sample_type, $project_additional_info, $full_count) = $h->fetchrow_array()) { my $location_name = $location_id ? $locations{$location_id} : ''; my $project_harvest_date = $harvest_date ? $calendar_funcs->display_start_date($harvest_date) : ''; my $project_planting_date = $planting_date ? $calendar_funcs->display_start_date($planting_date) : ''; @@ -369,33 +372,34 @@ sub search { } push @result, { - trial_id => $study_id, - trial_name => $study_name, - description => $study_description, - folder_id => $folder_id, - folder_name => $folder_name, - folder_description => $folder_description, - trial_type => $trial_type_name, - trial_type_name => $trial_type_name, - trial_type_id => $trial_type_id, - trial_type_value => $trial_type_value, - year => $year, - location_id => $location_id, - location_name => $location_name, - breeding_program_id => $breeding_program_id, - breeding_program_name => $breeding_program_name, - breeding_program_description => $breeding_program_description, - project_harvest_date => $project_harvest_date, - project_planting_date => $project_planting_date, - design => $design, - genotyping_facility => $genotyping_facility, + trial_id => $study_id, + trial_name => $study_name, + description => $study_description, + folder_id => $folder_id, + folder_name => $folder_name, + folder_description => $folder_description, + trial_type => $trial_type_name, + trial_type_name => $trial_type_name, + trial_type_id => $trial_type_id, + trial_type_value => $trial_type_value, + year => $year, + location_id => $location_id, + location_name => $location_name, + breeding_program_id => $breeding_program_id, + breeding_program_name => $breeding_program_name, + breeding_program_description => $breeding_program_description, + project_harvest_date => $project_harvest_date, + project_planting_date => $project_planting_date, + design => $design, + genotyping_facility => $genotyping_facility, genotyping_facility_submitted => $genotyping_facility_submitted, - genotyping_facility_status => $genotyping_facility_status, - genotyping_plate_format => $genotyping_plate_format, - genotyping_plate_sample_type => $genotyping_plate_sample_type, - genotyping_facility_plate_id => $genotyping_facility_plate_id, - sampling_facility => $sampling_facility, - sampling_trial_sample_type => $sampling_facility_sample_type + genotyping_facility_status => $genotyping_facility_status, + genotyping_plate_format => $genotyping_plate_format, + genotyping_plate_sample_type => $genotyping_plate_sample_type, + genotyping_facility_plate_id => $genotyping_facility_plate_id, + sampling_facility => $sampling_facility, + sampling_trial_sample_type => $sampling_facility_sample_type, + additional_info => $project_additional_info ? decode_json($project_additional_info) : undef }; $total_count = $full_count; } diff --git a/lib/CXGN/Trial/TrialCreate.pm b/lib/CXGN/Trial/TrialCreate.pm index 2ee5ed2f2e..294aa2e01e 100644 --- a/lib/CXGN/Trial/TrialCreate.pm +++ b/lib/CXGN/Trial/TrialCreate.pm @@ -163,6 +163,7 @@ has 'planting_date' => (isa => 'Str', is => 'rw', predicate => 'has_planting_dat has 'harvest_date' => (isa => 'Str', is => 'rw', predicate => 'has_harvest_date', required => 0); has 'operator' => (isa => 'Str', is => 'rw', predicate => 'has_operator', required => 1); has 'trial_stock_type' => (isa => 'Str', is => 'rw', predicate => 'has_trial_stock_type', required => 0, default => 'accession'); +has 'additional_info' => (isa => 'Maybe[HashRef]', is => 'rw', required => 0); # Trial linkage when saving a field trial # From 411c1c13fe4487317c9941e8989e3cd614d37e73 Mon Sep 17 00:00:00 2001 From: Chris T Date: Fri, 28 May 2021 10:24:41 -0400 Subject: [PATCH 05/14] fix brapi study locations for put and post --- lib/CXGN/BrAPI/v2/Studies.pm | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/CXGN/BrAPI/v2/Studies.pm b/lib/CXGN/BrAPI/v2/Studies.pm index 8de933f638..32a3a516f1 100644 --- a/lib/CXGN/BrAPI/v2/Studies.pm +++ b/lib/CXGN/BrAPI/v2/Studies.pm @@ -172,7 +172,8 @@ sub store { my $trial_name = $params->{studyName} ? $params->{studyName} : undef; my $trial_description = $params->{studyDescription} ? $params->{studyDescription} : undef; my $trial_year = $params->{seasons} ? $params->{seasons}->[0] : undef; - my $trial_location = $params->{locationName} ? $params->{locationName} : undef; + my $trial_location; + my $trial_location_id = $params->{locationDbId} ? $params->{locationDbId} : undef; my $trial_design_method = $params->{experimentalDesign} ? $params->{experimentalDesign}->{PUI} : undef; #Design type must be either: genotyping_plate, CRD, Alpha, Augmented, Lattice, RCBD, MAD, p-rep, greenhouse, or splitplot; my $folder_id = $params->{trialDbId} ? $params->{trialDbId} : undef; my $study_type = $params->{studyType} ? $params->{studyType} : undef; @@ -204,6 +205,17 @@ sub store { $program = $folder->name(); } + # Check that the location exists if it was passed in + if ($trial_location_id) { + my $location = $schema->resultset('NaturalDiversity::NdGeolocation')->find({nd_geolocation_id => $trial_location_id}); + if (!$location) { + my $err_string = sprintf('Location with id %s does not exist.',$trial_location_id); + warn $err_string; + return CXGN::BrAPI::JSONResponse->return_error($self->status, $err_string, 404); + } + $trial_location = $location->description(); + } + # Check that a study with this name does not already exist my $metadata_schema = $self->metadata_schema; my $phenome_schema = $self->phenome_schema; @@ -390,6 +402,16 @@ sub update { # Get the breeding program for that brapi trial my $program = $folder->breeding_program->project_id(); + # Check that the location exists if it was passed in + if ($study_location) { + my $location = $schema->resultset('NaturalDiversity::NdGeolocation')->find({nd_geolocation_id => $study_location}); + if (!$location) { + my $err_string = sprintf('Location with id %s does not exist.',$study_location); + warn $err_string; + return CXGN::BrAPI::JSONResponse->return_error($self->status, $err_string, 404); + } + } + # eval { # Use the misc_trial type if it doesn't match any of the other ones. @@ -700,7 +722,7 @@ sub _save_trial { # Check if a location was passed, set as N/A location if it does not exist my $geolocation; - if (defined $self->get_trial_location()) { + if ($self->has_trial_location()) { my $geolocation_lookup = CXGN::Location::LocationLookup->new(schema => $chado_schema); $geolocation_lookup->set_location_name($self->get_trial_location()); $geolocation = $geolocation_lookup->get_geolocation(); From aa6588a441b5a0a25c90bdf467dd50abbf38c52d Mon Sep 17 00:00:00 2001 From: Chris T Date: Fri, 28 May 2021 10:24:59 -0400 Subject: [PATCH 06/14] remove default N/A location when posting studies --- lib/CXGN/BrAPI/v2/Studies.pm | 32 ++++---------------------------- lib/SGN/Controller/AJAX/BrAPI.pm | 4 ++-- 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/lib/CXGN/BrAPI/v2/Studies.pm b/lib/CXGN/BrAPI/v2/Studies.pm index 32a3a516f1..9e53a5f0ce 100644 --- a/lib/CXGN/BrAPI/v2/Studies.pm +++ b/lib/CXGN/BrAPI/v2/Studies.pm @@ -172,7 +172,6 @@ sub store { my $trial_name = $params->{studyName} ? $params->{studyName} : undef; my $trial_description = $params->{studyDescription} ? $params->{studyDescription} : undef; my $trial_year = $params->{seasons} ? $params->{seasons}->[0] : undef; - my $trial_location; my $trial_location_id = $params->{locationDbId} ? $params->{locationDbId} : undef; my $trial_design_method = $params->{experimentalDesign} ? $params->{experimentalDesign}->{PUI} : undef; #Design type must be either: genotyping_plate, CRD, Alpha, Augmented, Lattice, RCBD, MAD, p-rep, greenhouse, or splitplot; my $folder_id = $params->{trialDbId} ? $params->{trialDbId} : undef; @@ -206,6 +205,7 @@ sub store { } # Check that the location exists if it was passed in + my $trial_location; if ($trial_location_id) { my $location = $schema->resultset('NaturalDiversity::NdGeolocation')->find({nd_geolocation_id => $trial_location_id}); if (!$location) { @@ -565,7 +565,6 @@ sub _search { }; # Join the additional info with the existing additional info if ($_->{additional_info}) { - print Dumper($_->{additional_info}); foreach my $key (keys %{$_->{additional_info}}){ $additional_info->{$key} = $_->{additional_info}->{$key}; } @@ -721,32 +720,9 @@ sub _save_trial { print STDERR "TRIAL TYPE = ".ref($t)."!!!!\n"; # Check if a location was passed, set as N/A location if it does not exist - my $geolocation; - if ($self->has_trial_location()) { - my $geolocation_lookup = CXGN::Location::LocationLookup->new(schema => $chado_schema); - $geolocation_lookup->set_location_name($self->get_trial_location()); - $geolocation = $geolocation_lookup->get_geolocation(); - } else { - # Check if there is already a N/A location - my $na_location_name = 'N/A'; - my $geolocation_lookup = CXGN::Location::LocationLookup->new(schema => $chado_schema); - $geolocation_lookup->set_location_name($na_location_name); - $geolocation = $geolocation_lookup->get_geolocation(); - - if (! defined $geolocation){ - # Create a N/A location - $geolocation = CXGN::Location->new( { - bcs_schema => $chado_schema, - name => $na_location_name - }); - my $store = $geolocation->store_location(); - if (defined $store->{error}) { - return $store; - } else { - $geolocation->nd_geolocation_id($store->{nd_geolocation_id}); - } - } - } + my $geolocation_lookup = CXGN::Location::LocationLookup->new(schema => $chado_schema); + $geolocation_lookup->set_location_name($self->get_trial_location()); + my $geolocation = $geolocation_lookup->get_geolocation(); my $nd_experiment_type_id = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'field_layout', 'experiment_type')->cvterm_id(); my $nd_experiment = $chado_schema->resultset('NaturalDiversity::NdExperiment') diff --git a/lib/SGN/Controller/AJAX/BrAPI.pm b/lib/SGN/Controller/AJAX/BrAPI.pm index f3b8c7ae46..bdb9eaae32 100644 --- a/lib/SGN/Controller/AJAX/BrAPI.pm +++ b/lib/SGN/Controller/AJAX/BrAPI.pm @@ -2037,7 +2037,7 @@ sub studies_POST { my ($auth, $user_id) = _authenticate_user($c); my $clean_inputs = $c->stash->{clean_inputs}; my $data = $clean_inputs; - _validate_request($c, 'ARRAY', $data, ['trialDbId', 'studyName', 'studyType']); + _validate_request($c, 'ARRAY', $data, ['trialDbId', 'studyName', 'studyType', 'locationDbId']); my @all_studies; foreach my $study (values %{$data}) { @@ -2182,7 +2182,7 @@ sub studies_info_PUT { my ($auth,$user_id) = _authenticate_user($c); my $clean_inputs = $c->stash->{clean_inputs}; my $data = $clean_inputs; - _validate_request($c, 'HASH', $data, ['trialDbId', 'studyName', 'studyType']); + _validate_request($c, 'HASH', $data, ['trialDbId', 'studyName', 'studyType', 'locationDbId']); $data->{studyDbId} = $c->stash->{study_id}; my $brapi = $self->brapi_module; From b1bfd4e1b78d257cf6a7632bfea23aee44cddb5e Mon Sep 17 00:00:00 2001 From: Chris T Date: Fri, 28 May 2021 10:25:30 -0400 Subject: [PATCH 07/14] touch ups to brapi study endpoints --- lib/CXGN/BrAPI/v2/Studies.pm | 1 - lib/SGN/Controller/AJAX/BrAPI.pm | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/CXGN/BrAPI/v2/Studies.pm b/lib/CXGN/BrAPI/v2/Studies.pm index 9e53a5f0ce..1b3e476bf4 100644 --- a/lib/CXGN/BrAPI/v2/Studies.pm +++ b/lib/CXGN/BrAPI/v2/Studies.pm @@ -719,7 +719,6 @@ sub _save_trial { print STDERR "TRIAL TYPE = ".ref($t)."!!!!\n"; - # Check if a location was passed, set as N/A location if it does not exist my $geolocation_lookup = CXGN::Location::LocationLookup->new(schema => $chado_schema); $geolocation_lookup->set_location_name($self->get_trial_location()); my $geolocation = $geolocation_lookup->get_geolocation(); diff --git a/lib/SGN/Controller/AJAX/BrAPI.pm b/lib/SGN/Controller/AJAX/BrAPI.pm index bdb9eaae32..91a2ddcf5c 100644 --- a/lib/SGN/Controller/AJAX/BrAPI.pm +++ b/lib/SGN/Controller/AJAX/BrAPI.pm @@ -138,13 +138,13 @@ sub brapi : Chained('/') PathPart('brapi') CaptureArgs(1) { if (defined $c->request->data){ if ($c->request->method eq "POST"){ if (ref $c->request->data ne 'ARRAY') { - my $response = CXGN::BrAPI::JSONResponse->return_error($c->stash->{status}, 'Array data type required', 400); + my $response = CXGN::BrAPI::JSONResponse->return_error($c->stash->{status}, 'JSON array body required', 400); _standard_response_construction($c, $response); } $c->stash->{clean_inputs} = _clean_inputs($c->req->params,$c->request->data); } elsif ($c->request->method eq "PUT") { if (ref $c->request->data eq 'ARRAY') { - my $response = CXGN::BrAPI::JSONResponse->return_error($c->stash->{status}, 'Hash data type required', 400); + my $response = CXGN::BrAPI::JSONResponse->return_error($c->stash->{status}, 'JSON hash body required', 400); _standard_response_construction($c, $response); } $c->stash->{clean_inputs} = $c->request->data; From 9889a32c95df3416cd6d15300a94a7bcc9b074ac Mon Sep 17 00:00:00 2001 From: Chris T Date: Fri, 28 May 2021 10:39:09 -0400 Subject: [PATCH 08/14] ignore query params on brapi post body check --- lib/SGN/Controller/AJAX/BrAPI.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/SGN/Controller/AJAX/BrAPI.pm b/lib/SGN/Controller/AJAX/BrAPI.pm index 91a2ddcf5c..f941d7cc14 100644 --- a/lib/SGN/Controller/AJAX/BrAPI.pm +++ b/lib/SGN/Controller/AJAX/BrAPI.pm @@ -207,8 +207,8 @@ sub _validate_request { if ($data_type eq 'ARRAY') { foreach my $object (values %{$data}) { foreach my $required_field (@{$required_fields}) { - print $required_field; - if (!$object->{$required_field}) { + # Ignore the query params if they were passed in + if (ref($object) eq 'HASH' && !$object->{$required_field}) { my $response = CXGN::BrAPI::JSONResponse->return_error($c->stash->{status}, sprintf('%s required', $required_field), 400); _standard_response_construction($c, $response); } From 34d00b99a8dbe08dea03365f7f411bfdf026d22e Mon Sep 17 00:00:00 2001 From: Chris T Date: Fri, 28 May 2021 12:01:48 -0400 Subject: [PATCH 09/14] fix brapi study tests --- t/unit_mech/AJAX/BrAPI_v2.t | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/t/unit_mech/AJAX/BrAPI_v2.t b/t/unit_mech/AJAX/BrAPI_v2.t index e52f2cadf8..fab5e13f4d 100644 --- a/t/unit_mech/AJAX/BrAPI_v2.t +++ b/t/unit_mech/AJAX/BrAPI_v2.t @@ -366,7 +366,7 @@ is_deeply($response, {'result' => {'data' => ['Cassava']},'metadata' => {'datafi $mech->get_ok('http://localhost:3010/brapi/v2/studies/?pageSize=3'); $response = decode_json $mech->content; print STDERR Dumper $response; -is_deeply($response, {'result' => {'data' => [{'locationName' => 'test_location','environmentParameters' => undef,'culturalPractices' => undef,'endDate' => undef,'observationUnitsDescription' => undef,'dataLinks' => [],'studyDbId' => '165','observationLevels' => undef,'documentationURL' => '','growthFacility' => undef,'externalReferences' => undef,'studyName' => 'CASS_6Genotypes_Sampling_2015','studyPUI' => undef,'studyType' => 'Preliminary Yield Trial','commonCropName' => 'Cassava','startDate' => undef,'experimentalDesign' => {'PUI' => undef,'description' => 'RCBD'},'contacts' => undef,'trialDbId' => '134','seasons' => ['2017'],'license' => '','trialName' => 'test','locationDbId' => '23','studyCode' => '165','studyDescription' => 'Copy of trial with postcomposed phenotypes from cassbase.','lastUpdate' => undef,'active' => JSON::true,'additionalInfo' => {'programName' => 'test','programDbId' => '134'}},{'license' => '','seasons' => ['2014'],'trialDbId' => '134','contacts' => undef,'additionalInfo' => {'programDbId' => '134','programName' => 'test'},'active' => JSON::true,'lastUpdate' => undef,'studyDescription' => 'This trial was loaded into the fixture to test solgs.','studyCode' => '139','locationDbId' => '23','trialName' => 'test','observationLevels' => undef,'studyDbId' => '139','dataLinks' => [],'observationUnitsDescription' => undef,'culturalPractices' => undef,'endDate' => undef,'environmentParameters' => undef,'locationName' => 'test_location','experimentalDesign' => {'PUI' => undef,'description' => 'Alpha'},'startDate' => undef,'commonCropName' => 'Cassava','studyType' => 'Clonal Evaluation','studyPUI' => undef,'studyName' => 'Kasese solgs trial','externalReferences' => undef,'growthFacility' => undef,'documentationURL' => ''},{'experimentalDesign' => {},'startDate' => undef,'commonCropName' => 'Cassava','studyType' => undef,'studyPUI' => undef,'studyName' => 'new_test_cross','externalReferences' => undef,'growthFacility' => undef,'documentationURL' => '','observationLevels' => undef,'dataLinks' => [],'studyDbId' => '135','observationUnitsDescription' => undef,'endDate' => undef,'culturalPractices' => undef,'environmentParameters' => undef,'locationName' => '','additionalInfo' => {'programDbId' => '134','programName' => 'test'},'active' => JSON::true,'lastUpdate' => undef,'studyDescription' => 'new_test_cross','studyCode' => '135','locationDbId' => undef,'trialName' => 'test','license' => '','contacts' => undef,'seasons' => [undef],'trialDbId' => '134'}]},'metadata' => {'datafiles' => [],'pagination' => {'totalCount' => 6,'totalPages' => 2,'currentPage' => 0,'pageSize' => 3},'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=3'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'messageType' => 'INFO','message' => 'Studies search result constructed'}]}}); +is_deeply($response, {'result' => {'data' => [{'locationName' => 'test_location','environmentParameters' => undef,'culturalPractices' => undef,'endDate' => undef,'observationUnitsDescription' => undef,'dataLinks' => [],'studyDbId' => '165','observationLevels' => undef,'documentationURL' => '','growthFacility' => undef,'externalReferences' => undef,'studyName' => 'CASS_6Genotypes_Sampling_2015','studyPUI' => undef,'studyType' => 'Preliminary Yield Trial','commonCropName' => 'Cassava','startDate' => undef,'experimentalDesign' => {'PUI' => undef,'description' => 'RCBD'},'contacts' => undef,'trialDbId' => '134','seasons' => ['2017'],'license' => '','trialName' => 'test','locationDbId' => '23','studyCode' => undef,'studyDescription' => 'Copy of trial with postcomposed phenotypes from cassbase.','lastUpdate' => undef,'active' => JSON::true,'additionalInfo' => {'programName' => 'test','programDbId' => '134'}},{'license' => '','seasons' => ['2014'],'trialDbId' => '134','contacts' => undef,'additionalInfo' => {'programDbId' => '134','programName' => 'test'},'active' => JSON::true,'lastUpdate' => undef,'studyDescription' => 'This trial was loaded into the fixture to test solgs.','studyCode' => undef,'locationDbId' => '23','trialName' => 'test','observationLevels' => undef,'studyDbId' => '139','dataLinks' => [],'observationUnitsDescription' => undef,'culturalPractices' => undef,'endDate' => undef,'environmentParameters' => undef,'locationName' => 'test_location','experimentalDesign' => {'PUI' => undef,'description' => 'Alpha'},'startDate' => undef,'commonCropName' => 'Cassava','studyType' => 'Clonal Evaluation','studyPUI' => undef,'studyName' => 'Kasese solgs trial','externalReferences' => undef,'growthFacility' => undef,'documentationURL' => ''},{'experimentalDesign' => {},'startDate' => undef,'commonCropName' => 'Cassava','studyType' => undef,'studyPUI' => undef,'studyName' => 'new_test_cross','externalReferences' => undef,'growthFacility' => undef,'documentationURL' => '','observationLevels' => undef,'dataLinks' => [],'studyDbId' => '135','observationUnitsDescription' => undef,'endDate' => undef,'culturalPractices' => undef,'environmentParameters' => undef,'locationName' => '','additionalInfo' => {'programDbId' => '134','programName' => 'test'},'active' => JSON::true,'lastUpdate' => undef,'studyDescription' => 'new_test_cross','studyCode' => undef,'locationDbId' => undef,'trialName' => 'test','license' => '','contacts' => undef,'seasons' => [undef],'trialDbId' => '134'}]},'metadata' => {'datafiles' => [],'pagination' => {'totalCount' => 6,'totalPages' => 2,'currentPage' => 0,'pageSize' => 3},'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=3'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'messageType' => 'INFO','message' => 'Studies search result constructed'}]}}); $mech->post_ok('http://localhost:3010/brapi/v2/search/studies', ['pageSize'=>'2', 'page'=>'2']); $response = decode_json $mech->content; @@ -374,11 +374,11 @@ $searchId = $response->{result} ->{searchResultDbId}; $mech->get_ok('http://localhost:3010/brapi/v2/search/studies/'. $searchId); $response = decode_json $mech->content; print STDERR Dumper $response; -is_deeply($response, {'result' => {'data' => [{'studyDescription' => 'test trial','studyCode' => '137','lastUpdate' => undef,'observationUnitsDescription' => undef,'experimentalDesign' => {'PUI' => undef,'description' => 'CRD'},'environmentParameters' => undef,'externalReferences' => undef,'studyType' => undef,'locationName' => 'test_location','commonCropName' => 'Cassava','growthFacility' => undef,'startDate' => '2017-07-04','studyName' => 'test_trial','trialDbId' => '134','studyPUI' => undef,'license' => '','additionalInfo' => {'programName' => 'test','programDbId' => '134'},'locationDbId' => '23','observationLevels' => undef,'contacts' => undef,'seasons' => ['2014'],'endDate' => '2017-07-21','studyDbId' => '137','trialName' => 'test','dataLinks' => [],'active' => JSON::true,'culturalPractices' => undef,'documentationURL' => ''},{'trialName' => 'test','studyDbId' => '141','documentationURL' => '','culturalPractices' => undef,'dataLinks' => [],'active' => JSON::true,'contacts' => undef,'endDate' => undef,'seasons' => ['2014'],'observationLevels' => undef,'trialDbId' => '134','startDate' => undef,'studyName' => 'trial2 NaCRRI','locationDbId' => '23','additionalInfo' => {'programName' => 'test','programDbId' => '134'},'license' => '','studyPUI' => undef,'commonCropName' => 'Cassava','locationName' => 'test_location','growthFacility' => undef,'externalReferences' => undef,'environmentParameters' => undef,'studyType' => undef,'observationUnitsDescription' => undef,'lastUpdate' => undef,'experimentalDesign' => {'PUI' => undef,'description' => 'CRD'},'studyDescription' => 'another trial for solGS','studyCode' => '141'}]},'metadata' => {'pagination' => {'totalCount' => 2,'pageSize' => 10,'totalPages' => 1,'currentPage' => 0},'status' => [{'message' => 'BrAPI base call found with page=0, pageSize=10','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Results'},{'messageType' => 'INFO','message' => 'search result constructed'}],'datafiles' => []}}); +is_deeply($response, {'result' => {'data' => [{'studyDescription' => 'test trial','studyCode' => undef,'lastUpdate' => undef,'observationUnitsDescription' => undef,'experimentalDesign' => {'PUI' => undef,'description' => 'CRD'},'environmentParameters' => undef,'externalReferences' => undef,'studyType' => undef,'locationName' => 'test_location','commonCropName' => 'Cassava','growthFacility' => undef,'startDate' => '2017-07-04','studyName' => 'test_trial','trialDbId' => '134','studyPUI' => undef,'license' => '','additionalInfo' => {'programName' => 'test','programDbId' => '134'},'locationDbId' => '23','observationLevels' => undef,'contacts' => undef,'seasons' => ['2014'],'endDate' => '2017-07-21','studyDbId' => '137','trialName' => 'test','dataLinks' => [],'active' => JSON::true,'culturalPractices' => undef,'documentationURL' => ''},{'trialName' => 'test','studyDbId' => '141','documentationURL' => '','culturalPractices' => undef,'dataLinks' => [],'active' => JSON::true,'contacts' => undef,'endDate' => undef,'seasons' => ['2014'],'observationLevels' => undef,'trialDbId' => '134','startDate' => undef,'studyName' => 'trial2 NaCRRI','locationDbId' => '23','additionalInfo' => {'programName' => 'test','programDbId' => '134'},'license' => '','studyPUI' => undef,'commonCropName' => 'Cassava','locationName' => 'test_location','growthFacility' => undef,'externalReferences' => undef,'environmentParameters' => undef,'studyType' => undef,'observationUnitsDescription' => undef,'lastUpdate' => undef,'experimentalDesign' => {'PUI' => undef,'description' => 'CRD'},'studyDescription' => 'another trial for solGS','studyCode' => undef}]},'metadata' => {'pagination' => {'totalCount' => 2,'pageSize' => 10,'totalPages' => 1,'currentPage' => 0},'status' => [{'message' => 'BrAPI base call found with page=0, pageSize=10','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Results'},{'messageType' => 'INFO','message' => 'search result constructed'}],'datafiles' => []}}); $mech->get_ok('http://localhost:3010/brapi/v2/studies/139'); $response = decode_json $mech->content; print STDERR Dumper $response; -is_deeply($response, {'metadata' => {'pagination' => {'totalCount' => 1,'totalPages' => 1,'currentPage' => 0,'pageSize' => 10},'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=10'},{'message' => 'Loading CXGN::BrAPI::v2::Studies','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Studies detail result constructed'}],'datafiles' => []},'result' => {'studyCode' => '139','trialDbId' => '134','environmentParameters' => undef,'externalReferences' => undef,'dataLinks' => [],'commonCropName' => 'Cassava','studyType' => 'Clonal Evaluation','additionalInfo' => {},'documentationURL' => '','endDate' => undef,'studyDescription' => 'This trial was loaded into the fixture to test solgs.','studyName' => 'Kasese solgs trial','locationName' => 'test_location','studyPUI' => undef,'lastUpdate' => undef,'experimentalDesign' => {'PUI' => undef,'description' => 'Alpha'},'observationUnitsDescription' => undef,'startDate' => undef,'studyDbId' => '139','observationLevels' => undef,'culturalPractices' => undef,'growthFacility' => undef,'locationDbId' => '23','seasons' => ['2014'],'contacts' => undef,'active' => JSON::true ,'trialName' => 'test','license' => ''}} ); +is_deeply($response, {'metadata' => {'pagination' => {'totalCount' => 1,'totalPages' => 1,'currentPage' => 0,'pageSize' => 10},'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=10'},{'message' => 'Loading CXGN::BrAPI::v2::Studies','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Studies search result constructed'}],'datafiles' => []},'result' => {'studyCode' => undef,'trialDbId' => '134','environmentParameters' => undef,'externalReferences' => undef,'dataLinks' => [],'commonCropName' => 'Cassava','studyType' => 'Clonal Evaluation','additionalInfo' => {'programDbId' => '134', 'programName' => 'test'},'documentationURL' => '','endDate' => undef,'studyDescription' => 'This trial was loaded into the fixture to test solgs.','studyName' => 'Kasese solgs trial','locationName' => 'test_location','studyPUI' => undef,'lastUpdate' => undef,'experimentalDesign' => {'PUI' => undef,'description' => 'Alpha'},'observationUnitsDescription' => undef,'startDate' => undef,'studyDbId' => '139','observationLevels' => undef,'culturalPractices' => undef,'growthFacility' => undef,'locationDbId' => '23','seasons' => ['2014'],'contacts' => undef,'active' => JSON::true ,'trialName' => 'test','license' => ''}} ); $mech->get_ok('http://localhost:3010/brapi/v2/locations?pageSize=3'); $response = decode_json $mech->content; @@ -461,20 +461,20 @@ $data = '[ { "active": "true", "additionalInfo": {}, "commonCropName": "Grape", $mech->post('http://localhost:3010/brapi/v2/studies', Content => $data); $response = decode_json $mech->content; print STDERR Dumper $response; -is_deeply($response, {'result' => {'data' => [{'observationLevels' => undef,'dataLinks' => [],'experimentalDesign' => {'PUI' => undef,'description' => 'RCBD'},'observationUnitsDescription' => undef,'studyName' => 'Observation at Kenya 1','startDate' => undef,'growthFacility' => undef,'active' => JSON::true,'lastUpdate' => undef,'contacts' => undef,'endDate' => undef,'studyDbId' => '169','locationDbId' => '23','documentationURL' => '','additionalInfo' => {'programDbId' => '134','programName' => 'test'},'seasons' => ['2018'],'culturalPractices' => undef,'studyDescription' => 'This is a yield study for Spring 2018','externalReferences' => undef,'studyPUI' => undef,'commonCropName' => 'Cassava','trialDbId' => '168','studyType' => 'phenotyping_trial','trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location','license' => '','studyCode' => '169','environmentParameters' => undef}]},'metadata' => {'datafiles' => [],'pagination' => {'totalCount' => 1,'currentPage' => 0,'pageSize' => 10,'totalPages' => 1},'status' => [{'message' => 'BrAPI base call found with page=0, pageSize=10','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'message' => 'Studies stored successfully','messageType' => 'INFO'}]}} ); +is_deeply($response, {'result' => {'data' => [{'observationLevels' => undef,'dataLinks' => [],'experimentalDesign' => {'PUI' => undef,'description' => 'RCBD'},'observationUnitsDescription' => undef,'studyName' => 'Observation at Kenya 1','startDate' => undef,'growthFacility' => undef,'active' => JSON::true,'lastUpdate' => undef,'contacts' => undef,'endDate' => undef,'studyDbId' => '169','locationDbId' => '23','documentationURL' => '','additionalInfo' => {'programDbId' => '134','programName' => 'test'},'seasons' => ['2018'],'culturalPractices' => undef,'studyDescription' => 'This is a yield study for Spring 2018','externalReferences' => undef,'studyPUI' => undef,'commonCropName' => 'Cassava','trialDbId' => '168','studyType' => 'phenotyping_trial','trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location','license' => '','studyCode' => undef,'environmentParameters' => undef}]},'metadata' => {'datafiles' => [],'pagination' => {'totalCount' => 1,'currentPage' => 0,'pageSize' => 10,'totalPages' => 1},'status' => [{'message' => 'BrAPI base call found with page=0, pageSize=10','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'message' => 'Studies stored successfully','messageType' => 'INFO'}]}} ); $data = '{ "active": "true", "additionalInfo": {}, "commonCropName": "Grape", "contacts": [], "culturalPractices": "Irrigation was applied according needs during summer to prevent water stress.", "dataLinks": [], "documentationURL": "http://breedbase.org", "endDate": "2018-01-01", "environmentParameters": [ { "description": "the soil type was clay", "parameterName": "soil type", "parameterPUI": "PECO:0007155", "unit": "pH", "unitPUI": "PECO:0007059", "value": "clay soil", "valuePUI": "ENVO:00002262" } ], "experimentalDesign": { "PUI": "CO_715:0000145", "description": "Lines were repeated twice at each location using a complete block design. In order to limit competition effects, each block was organized into four sub-blocks corresponding to earliest groups based on a prior information." }, "externalReferences": [], "growthFacility": { "PUI": "CO_715:0000162", "description": "field environment condition, greenhouse" }, "lastUpdate": { "timestamp": "2018-01-01T14:47:23-0600", "version": "1.2.3" }, "license": "MIT License", "locationDbId": "23", "locationName": "test_location", "observationLevels": [], "observationUnitsDescription": "Observation units consisted in individual plots themselves consisting of a row of 15 plants at a density of approximately six plants per square meter.", "seasons": [ "Spring_2018" ], "startDate": "2018-01-01", "studyCode": "Grape_Yield_Spring_2018", "studyDescription": "This is a yield study for Spring 2018", "studyName": "INRAs Walnut Genetic Resources Observation at Kenya modified", "studyPUI": "doi:10.155454/12349537312", "studyType": "phenotyping_trial", "trialDbId": "168", "trialName": "Peru Yield Trial 2010"}'; $resp = $ua->put("http://localhost:3010/brapi/v2/studies/139", Content => $data); $response = decode_json $resp->{_content}; print STDERR Dumper $response; -is_deeply($response, {'result' => {'data' => [{'culturalPractices' => undef,'studyDescription' => 'This is a yield study for Spring 2018','externalReferences' => undef,'studyPUI' => undef,'commonCropName' => 'Cassava','trialDbId' => '168','studyType' => 'phenotyping_trial','additionalInfo' => {'programName' => 'test','programDbId' => '134'},'seasons' => ['Spring_2018'],'environmentParameters' => undef,'trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location','studyCode' => '139','license' => '','observationUnitsDescription' => undef,'studyName' => 'INRAs Walnut Genetic Resources Observation at Kenya modified','startDate' => '2018-01-01','growthFacility' => undef,'active' => JSON::true,'lastUpdate' => undef,'observationLevels' => undef,'dataLinks' => [],'experimentalDesign' => {'PUI' => undef,'description' => 'CO_715:0000145'},'locationDbId' => '23','documentationURL' => '','contacts' => undef,'endDate' => '2018-01-01','studyDbId' => '139'}]},'metadata' => {'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=10'},{'message' => 'Loading CXGN::BrAPI::v2::Studies','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Studies result constructed'}],'datafiles' => [],'pagination' => {'totalCount' => 1,'totalPages' => 1,'pageSize' => 10,'currentPage' => 0}}} ); +is_deeply($response, {'result' => {'culturalPractices' => undef,'studyDescription' => 'This is a yield study for Spring 2018','externalReferences' => undef,'studyPUI' => undef,'commonCropName' => 'Cassava','trialDbId' => '168','studyType' => 'phenotyping_trial','additionalInfo' => {'programName' => 'test','programDbId' => '134'},'seasons' => ['Spring_2018'],'environmentParameters' => undef,'trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location','studyCode' => undef,'license' => '','observationUnitsDescription' => undef,'studyName' => 'INRAs Walnut Genetic Resources Observation at Kenya modified','startDate' => '2018-01-01','growthFacility' => undef,'active' => JSON::true,'lastUpdate' => undef,'observationLevels' => undef,'dataLinks' => [],'experimentalDesign' => {'PUI' => undef,'description' => 'CO_715:0000145'},'locationDbId' => '23','documentationURL' => '','contacts' => undef,'endDate' => '2018-01-01','studyDbId' => '139'},'metadata' => {'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=10'},{'message' => 'Loading CXGN::BrAPI::v2::Studies','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Studies result constructed'}],'datafiles' => [],'pagination' => {'totalCount' => 1,'totalPages' => 1,'pageSize' => 10,'currentPage' => 0}}} ); # -$data = '{ "studyName": "Kasese solgs trial", "trialDbId": "139", "seasons": [ "2014" ]}'; +$data = '{ "studyName": "Kasese solgs trial", "trialDbId": "139", "seasons": [ "2014" ], "locationDbId":"23", "studyType":"phenotyping_trial"}'; $resp = $ua->put("http://localhost:3010/brapi/v2/studies/139", Content => $data); $response = decode_json $resp->{_content}; print STDERR Dumper $response; -is_deeply($response, {'result' => {'data' => [{'lastUpdate' => undef,'startDate' => '2018-01-01','active' => JSON::true,'growthFacility' => undef,'observationUnitsDescription' => undef,'studyName' => 'Kasese solgs trial','dataLinks' => [],'experimentalDesign' => {'PUI' => undef,'description' => 'CO_715:0000145'},'observationLevels' => undef,'documentationURL' => '','locationDbId' => '23','studyDbId' => '139','endDate' => '2018-01-01','contacts' => undef,'commonCropName' => 'Cassava','studyType' => 'phenotyping_trial','trialDbId' => '168','externalReferences' => undef,'studyPUI' => undef,'studyDescription' => 'This is a yield study for Spring 2018','culturalPractices' => undef,'seasons' => ['2014'],'additionalInfo' => {'programName' => 'test','programDbId' => '134'},'environmentParameters' => undef,'studyCode' => '139','license' => '','trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location'}]},'metadata' => {'pagination' => {'pageSize' => 10,'currentPage' => 0,'totalPages' => 1,'totalCount' => 1},'datafiles' => [],'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=10'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'messageType' => 'INFO','message' => 'Studies result constructed'}]}} ); +is_deeply($response, {'result' => {'lastUpdate' => undef,'startDate' => '2018-01-01','active' => JSON::true,'growthFacility' => undef,'observationUnitsDescription' => undef,'studyName' => 'Kasese solgs trial','dataLinks' => [],'experimentalDesign' => {'PUI' => undef,'description' => 'CO_715:0000145'},'observationLevels' => undef,'documentationURL' => '','locationDbId' => '23','studyDbId' => '139','endDate' => '2018-01-01','contacts' => undef,'commonCropName' => 'Cassava','studyType' => 'phenotyping_trial','trialDbId' => '168','externalReferences' => undef,'studyPUI' => undef,'studyDescription' => 'This is a yield study for Spring 2018','culturalPractices' => undef,'seasons' => ['2014'],'additionalInfo' => {'programName' => 'test','programDbId' => '134'},'environmentParameters' => undef,'studyCode' => undef,'license' => '','trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location'},'metadata' => {'pagination' => {'pageSize' => 10,'currentPage' => 0,'totalPages' => 1,'totalCount' => 1},'datafiles' => [],'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=10'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'messageType' => 'INFO','message' => 'Studies result constructed'}]}}); $data = '{ "41782": { "observationUnitName":"CASS_6Genotypes_201", "studyDbId": "169","studyName": "Observation at Kenya 1", "germplasmDbId": "41280", "germplasmName": "TMEB693", "externalReferences" :[], "observationUnitPosition": {"entryType": "TEST", "geoCoordinates": { "geometry": { "coordinates": [ -76.506042, 42.417373, 10 ], "type": "Point" }, "type": "Feature" }, "observationLevel": { "levelName": "plot", "levelOrder": 2, "levelCode": "Plot_123" }, "observationLevelRelationships": [ { "levelCode": "Field_1", "levelName": "field", "levelOrder": 0 }, { "levelCode": "Block_12", "levelName": "block", "levelOrder": 1 }, { "levelCode": "Plot_123", "levelName": "plot", "levelOrder": 2 } ], "positionCoordinateX": "74", "positionCoordinateXType": "GRID_COL", "positionCoordinateY": "03", "positionCoordinateYType": "GRID_ROW" } }, "41301":{ "externalReferences" :[], "observationUnitPosition": {"entryType": "TEST", "geoCoordinates": { "geometry": { "coordinates": [ -76.506042, 42.417373, 20 ], "type": "Point" }, "type": "Feature" }, "observationLevel": { "levelName": "plot", "levelOrder": 2, "levelCode": "Plot_123" }, "observationLevelRelationships": [ { "levelCode": "Field_1", "levelName": "field", "levelOrder": 0 }, { "levelCode": "Block_12", "levelName": "block", "levelOrder": 1 }, { "levelCode": "Plot_123", "levelName": "plot", "levelOrder": 2 } ], "positionCoordinateX": "74", "positionCoordinateXType": "GRID_COL", "positionCoordinateY": "03", "positionCoordinateYType": "GRID_ROW" } }}'; From 95b687163b9e66139e58d84afd1feb6dcb2da9ba Mon Sep 17 00:00:00 2001 From: Chris T Date: Wed, 2 Jun 2021 13:21:24 -0400 Subject: [PATCH 10/14] PR review changes, required design type, fix duplicate predicate --- lib/CXGN/BrAPI/v2/Studies.pm | 2 ++ lib/CXGN/Trial/TrialCreate.pm | 2 +- lib/SGN/Controller/AJAX/BrAPI.pm | 50 +++++++++++++++++++++++--------- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/lib/CXGN/BrAPI/v2/Studies.pm b/lib/CXGN/BrAPI/v2/Studies.pm index 1b3e476bf4..e2b30aa4e1 100644 --- a/lib/CXGN/BrAPI/v2/Studies.pm +++ b/lib/CXGN/BrAPI/v2/Studies.pm @@ -756,6 +756,8 @@ sub _save_trial { $project->create_projectprops({ $project_design_cvterm->name() => $self->get_design_type() }); + } else { + return {error => 'A design type is required'}; } if ($self->has_field_size && $self->get_field_size){ $project->create_projectprops({ diff --git a/lib/CXGN/Trial/TrialCreate.pm b/lib/CXGN/Trial/TrialCreate.pm index 294aa2e01e..b86536023b 100644 --- a/lib/CXGN/Trial/TrialCreate.pm +++ b/lib/CXGN/Trial/TrialCreate.pm @@ -153,7 +153,7 @@ has 'design_type' => (isa => 'Maybe[Str]', is => 'rw', predicate => 'has_design_ has 'design' => (isa => 'HashRef[HashRef]|Undef', is => 'rw', predicate => 'has_design', required => 0); has 'trial_name' => (isa => 'Str', is => 'rw', predicate => 'has_trial_name', required => 1); has 'trial_type' => (isa => 'Str', is => 'rw', predicate => 'has_trial_type', required => 1); -has 'trial_type_value' => (isa => 'Str', is => 'rw', predicate => 'has_trial_type', required => 0); +has 'trial_type_value' => (isa => 'Str', is => 'rw', predicate => 'has_trial_type_value', required => 0); has 'trial_has_plant_entries' => (isa => 'Int', is => 'rw', predicate => 'has_trial_has_plant_entries', required => 0); has 'trial_has_subplot_entries' => (isa => 'Int', is => 'rw', predicate => 'has_trial_has_subplot_entries', required => 0); has 'field_size' => (isa => 'Num', is => 'rw', predicate => 'has_field_size', required => 0); diff --git a/lib/SGN/Controller/AJAX/BrAPI.pm b/lib/SGN/Controller/AJAX/BrAPI.pm index f941d7cc14..95110f1710 100644 --- a/lib/SGN/Controller/AJAX/BrAPI.pm +++ b/lib/SGN/Controller/AJAX/BrAPI.pm @@ -200,31 +200,55 @@ sub _validate_request { my $data_type = shift; my $data = shift; my $required_fields = shift; + my $required_field_prefix = shift; - # Check the required fields - # TODO: Only top level right now, maybe in the future add nested checks if ($required_fields) { + # Validate each array element if ($data_type eq 'ARRAY') { foreach my $object (values %{$data}) { - foreach my $required_field (@{$required_fields}) { - # Ignore the query params if they were passed in - if (ref($object) eq 'HASH' && !$object->{$required_field}) { - my $response = CXGN::BrAPI::JSONResponse->return_error($c->stash->{status}, sprintf('%s required', $required_field), 400); - _standard_response_construction($c, $response); + # Ignore the query params if they were passed in. Their included in the body + if (ref($object) eq 'HASH') { + _validate_request($c, 'HASH', $object, $required_fields); + } + } + } + + # Check all of our fields + foreach my $required_field (@{$required_fields}) { + # Check if the required field has another level or not + if (ref($required_field) eq 'HASH') { + # Check the field keys and recurse + foreach my $sub_req_field (keys %{$required_field}) { + if ($data_type eq 'HASH') { + if (!$data->{$sub_req_field}) { + _missing_field_response($c, $sub_req_field, $required_field_prefix); + } else { + my $sub_data = $data->{$sub_req_field}; + _validate_request($c, 'HASH', $sub_data, $required_field->{$sub_req_field}, + $required_field_prefix ? sprintf("%s.%s", $required_field_prefix, $sub_req_field): $sub_req_field); + } } } + next; } - } elsif ($data_type eq 'HASH') { - foreach my $required_field (@{$required_fields}) { + + if ($data_type eq 'HASH') { if (!$data->{$required_field}) { - my $response = CXGN::BrAPI::JSONResponse->return_error($c->stash->{status}, sprintf('%s required', $required_field), 400); - _standard_response_construction($c, $response); + _missing_field_response($c, $required_field, $required_field_prefix); } } } } } +sub _missing_field_response { + my $c = shift; + my $field_name = shift; + my $prefix = shift; + my $response = CXGN::BrAPI::JSONResponse->return_error($c->stash->{status}, $prefix ? sprintf("%s.%s required", $prefix, $field_name) : $field_name, 400); + _standard_response_construction($c, $response); +} + sub _authenticate_user { my $c = shift; my $force_authenticate = shift; @@ -2037,7 +2061,7 @@ sub studies_POST { my ($auth, $user_id) = _authenticate_user($c); my $clean_inputs = $c->stash->{clean_inputs}; my $data = $clean_inputs; - _validate_request($c, 'ARRAY', $data, ['trialDbId', 'studyName', 'studyType', 'locationDbId']); + _validate_request($c, 'ARRAY', $data, ['trialDbId', 'studyName', 'studyType', 'locationDbId', {'experimentalDesign' => ['PUI']}]); my @all_studies; foreach my $study (values %{$data}) { @@ -2182,7 +2206,7 @@ sub studies_info_PUT { my ($auth,$user_id) = _authenticate_user($c); my $clean_inputs = $c->stash->{clean_inputs}; my $data = $clean_inputs; - _validate_request($c, 'HASH', $data, ['trialDbId', 'studyName', 'studyType', 'locationDbId']); + _validate_request($c, 'HASH', $data, ['trialDbId', 'studyName', 'studyType', 'locationDbId', {'experimentalDesign' => ['PUI']}]); $data->{studyDbId} = $c->stash->{study_id}; my $brapi = $self->brapi_module; From 355bb9a28c9395d55ceb3f8ac3cc80b1feb8d57a Mon Sep 17 00:00:00 2001 From: Chris T Date: Wed, 2 Jun 2021 13:46:40 -0400 Subject: [PATCH 11/14] return study design type in experimentalDesign.PUI - brapi studies --- lib/CXGN/BrAPI/v2/Studies.pm | 2 +- t/unit_mech/AJAX/BrAPI_v2.t | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/CXGN/BrAPI/v2/Studies.pm b/lib/CXGN/BrAPI/v2/Studies.pm index e2b30aa4e1..10328f4148 100644 --- a/lib/CXGN/BrAPI/v2/Studies.pm +++ b/lib/CXGN/BrAPI/v2/Studies.pm @@ -629,7 +629,7 @@ sub _search { if ($t->get_design_type()){ $experimental_design = { - PUI => undef, + PUI => $t->get_design_type(), description => $t->get_design_type() }; } diff --git a/t/unit_mech/AJAX/BrAPI_v2.t b/t/unit_mech/AJAX/BrAPI_v2.t index fab5e13f4d..087390264c 100644 --- a/t/unit_mech/AJAX/BrAPI_v2.t +++ b/t/unit_mech/AJAX/BrAPI_v2.t @@ -366,7 +366,7 @@ is_deeply($response, {'result' => {'data' => ['Cassava']},'metadata' => {'datafi $mech->get_ok('http://localhost:3010/brapi/v2/studies/?pageSize=3'); $response = decode_json $mech->content; print STDERR Dumper $response; -is_deeply($response, {'result' => {'data' => [{'locationName' => 'test_location','environmentParameters' => undef,'culturalPractices' => undef,'endDate' => undef,'observationUnitsDescription' => undef,'dataLinks' => [],'studyDbId' => '165','observationLevels' => undef,'documentationURL' => '','growthFacility' => undef,'externalReferences' => undef,'studyName' => 'CASS_6Genotypes_Sampling_2015','studyPUI' => undef,'studyType' => 'Preliminary Yield Trial','commonCropName' => 'Cassava','startDate' => undef,'experimentalDesign' => {'PUI' => undef,'description' => 'RCBD'},'contacts' => undef,'trialDbId' => '134','seasons' => ['2017'],'license' => '','trialName' => 'test','locationDbId' => '23','studyCode' => undef,'studyDescription' => 'Copy of trial with postcomposed phenotypes from cassbase.','lastUpdate' => undef,'active' => JSON::true,'additionalInfo' => {'programName' => 'test','programDbId' => '134'}},{'license' => '','seasons' => ['2014'],'trialDbId' => '134','contacts' => undef,'additionalInfo' => {'programDbId' => '134','programName' => 'test'},'active' => JSON::true,'lastUpdate' => undef,'studyDescription' => 'This trial was loaded into the fixture to test solgs.','studyCode' => undef,'locationDbId' => '23','trialName' => 'test','observationLevels' => undef,'studyDbId' => '139','dataLinks' => [],'observationUnitsDescription' => undef,'culturalPractices' => undef,'endDate' => undef,'environmentParameters' => undef,'locationName' => 'test_location','experimentalDesign' => {'PUI' => undef,'description' => 'Alpha'},'startDate' => undef,'commonCropName' => 'Cassava','studyType' => 'Clonal Evaluation','studyPUI' => undef,'studyName' => 'Kasese solgs trial','externalReferences' => undef,'growthFacility' => undef,'documentationURL' => ''},{'experimentalDesign' => {},'startDate' => undef,'commonCropName' => 'Cassava','studyType' => undef,'studyPUI' => undef,'studyName' => 'new_test_cross','externalReferences' => undef,'growthFacility' => undef,'documentationURL' => '','observationLevels' => undef,'dataLinks' => [],'studyDbId' => '135','observationUnitsDescription' => undef,'endDate' => undef,'culturalPractices' => undef,'environmentParameters' => undef,'locationName' => '','additionalInfo' => {'programDbId' => '134','programName' => 'test'},'active' => JSON::true,'lastUpdate' => undef,'studyDescription' => 'new_test_cross','studyCode' => undef,'locationDbId' => undef,'trialName' => 'test','license' => '','contacts' => undef,'seasons' => [undef],'trialDbId' => '134'}]},'metadata' => {'datafiles' => [],'pagination' => {'totalCount' => 6,'totalPages' => 2,'currentPage' => 0,'pageSize' => 3},'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=3'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'messageType' => 'INFO','message' => 'Studies search result constructed'}]}}); +is_deeply($response, {'result' => {'data' => [{'locationName' => 'test_location','environmentParameters' => undef,'culturalPractices' => undef,'endDate' => undef,'observationUnitsDescription' => undef,'dataLinks' => [],'studyDbId' => '165','observationLevels' => undef,'documentationURL' => '','growthFacility' => undef,'externalReferences' => undef,'studyName' => 'CASS_6Genotypes_Sampling_2015','studyPUI' => undef,'studyType' => 'Preliminary Yield Trial','commonCropName' => 'Cassava','startDate' => undef,'experimentalDesign' => {'PUI' => 'RCBD','description' => 'RCBD'},'contacts' => undef,'trialDbId' => '134','seasons' => ['2017'],'license' => '','trialName' => 'test','locationDbId' => '23','studyCode' => undef,'studyDescription' => 'Copy of trial with postcomposed phenotypes from cassbase.','lastUpdate' => undef,'active' => JSON::true,'additionalInfo' => {'programName' => 'test','programDbId' => '134'}},{'license' => '','seasons' => ['2014'],'trialDbId' => '134','contacts' => undef,'additionalInfo' => {'programDbId' => '134','programName' => 'test'},'active' => JSON::true,'lastUpdate' => undef,'studyDescription' => 'This trial was loaded into the fixture to test solgs.','studyCode' => undef,'locationDbId' => '23','trialName' => 'test','observationLevels' => undef,'studyDbId' => '139','dataLinks' => [],'observationUnitsDescription' => undef,'culturalPractices' => undef,'endDate' => undef,'environmentParameters' => undef,'locationName' => 'test_location','experimentalDesign' => {'PUI' => 'Alpha','description' => 'Alpha'},'startDate' => undef,'commonCropName' => 'Cassava','studyType' => 'Clonal Evaluation','studyPUI' => undef,'studyName' => 'Kasese solgs trial','externalReferences' => undef,'growthFacility' => undef,'documentationURL' => ''},{'experimentalDesign' => {},'startDate' => undef,'commonCropName' => 'Cassava','studyType' => undef,'studyPUI' => undef,'studyName' => 'new_test_cross','externalReferences' => undef,'growthFacility' => undef,'documentationURL' => '','observationLevels' => undef,'dataLinks' => [],'studyDbId' => '135','observationUnitsDescription' => undef,'endDate' => undef,'culturalPractices' => undef,'environmentParameters' => undef,'locationName' => '','additionalInfo' => {'programDbId' => '134','programName' => 'test'},'active' => JSON::true,'lastUpdate' => undef,'studyDescription' => 'new_test_cross','studyCode' => undef,'locationDbId' => undef,'trialName' => 'test','license' => '','contacts' => undef,'seasons' => [undef],'trialDbId' => '134'}]},'metadata' => {'datafiles' => [],'pagination' => {'totalCount' => 6,'totalPages' => 2,'currentPage' => 0,'pageSize' => 3},'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=3'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'messageType' => 'INFO','message' => 'Studies search result constructed'}]}}); $mech->post_ok('http://localhost:3010/brapi/v2/search/studies', ['pageSize'=>'2', 'page'=>'2']); $response = decode_json $mech->content; @@ -374,11 +374,11 @@ $searchId = $response->{result} ->{searchResultDbId}; $mech->get_ok('http://localhost:3010/brapi/v2/search/studies/'. $searchId); $response = decode_json $mech->content; print STDERR Dumper $response; -is_deeply($response, {'result' => {'data' => [{'studyDescription' => 'test trial','studyCode' => undef,'lastUpdate' => undef,'observationUnitsDescription' => undef,'experimentalDesign' => {'PUI' => undef,'description' => 'CRD'},'environmentParameters' => undef,'externalReferences' => undef,'studyType' => undef,'locationName' => 'test_location','commonCropName' => 'Cassava','growthFacility' => undef,'startDate' => '2017-07-04','studyName' => 'test_trial','trialDbId' => '134','studyPUI' => undef,'license' => '','additionalInfo' => {'programName' => 'test','programDbId' => '134'},'locationDbId' => '23','observationLevels' => undef,'contacts' => undef,'seasons' => ['2014'],'endDate' => '2017-07-21','studyDbId' => '137','trialName' => 'test','dataLinks' => [],'active' => JSON::true,'culturalPractices' => undef,'documentationURL' => ''},{'trialName' => 'test','studyDbId' => '141','documentationURL' => '','culturalPractices' => undef,'dataLinks' => [],'active' => JSON::true,'contacts' => undef,'endDate' => undef,'seasons' => ['2014'],'observationLevels' => undef,'trialDbId' => '134','startDate' => undef,'studyName' => 'trial2 NaCRRI','locationDbId' => '23','additionalInfo' => {'programName' => 'test','programDbId' => '134'},'license' => '','studyPUI' => undef,'commonCropName' => 'Cassava','locationName' => 'test_location','growthFacility' => undef,'externalReferences' => undef,'environmentParameters' => undef,'studyType' => undef,'observationUnitsDescription' => undef,'lastUpdate' => undef,'experimentalDesign' => {'PUI' => undef,'description' => 'CRD'},'studyDescription' => 'another trial for solGS','studyCode' => undef}]},'metadata' => {'pagination' => {'totalCount' => 2,'pageSize' => 10,'totalPages' => 1,'currentPage' => 0},'status' => [{'message' => 'BrAPI base call found with page=0, pageSize=10','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Results'},{'messageType' => 'INFO','message' => 'search result constructed'}],'datafiles' => []}}); +is_deeply($response, {'result' => {'data' => [{'studyDescription' => 'test trial','studyCode' => undef,'lastUpdate' => undef,'observationUnitsDescription' => undef,'experimentalDesign' => {'PUI' => 'CRD','description' => 'CRD'},'environmentParameters' => undef,'externalReferences' => undef,'studyType' => undef,'locationName' => 'test_location','commonCropName' => 'Cassava','growthFacility' => undef,'startDate' => '2017-07-04','studyName' => 'test_trial','trialDbId' => '134','studyPUI' => undef,'license' => '','additionalInfo' => {'programName' => 'test','programDbId' => '134'},'locationDbId' => '23','observationLevels' => undef,'contacts' => undef,'seasons' => ['2014'],'endDate' => '2017-07-21','studyDbId' => '137','trialName' => 'test','dataLinks' => [],'active' => JSON::true,'culturalPractices' => undef,'documentationURL' => ''},{'trialName' => 'test','studyDbId' => '141','documentationURL' => '','culturalPractices' => undef,'dataLinks' => [],'active' => JSON::true,'contacts' => undef,'endDate' => undef,'seasons' => ['2014'],'observationLevels' => undef,'trialDbId' => '134','startDate' => undef,'studyName' => 'trial2 NaCRRI','locationDbId' => '23','additionalInfo' => {'programName' => 'test','programDbId' => '134'},'license' => '','studyPUI' => undef,'commonCropName' => 'Cassava','locationName' => 'test_location','growthFacility' => undef,'externalReferences' => undef,'environmentParameters' => undef,'studyType' => undef,'observationUnitsDescription' => undef,'lastUpdate' => undef,'experimentalDesign' => {'PUI' => 'CRD','description' => 'CRD'},'studyDescription' => 'another trial for solGS','studyCode' => undef}]},'metadata' => {'pagination' => {'totalCount' => 2,'pageSize' => 10,'totalPages' => 1,'currentPage' => 0},'status' => [{'message' => 'BrAPI base call found with page=0, pageSize=10','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Results'},{'messageType' => 'INFO','message' => 'search result constructed'}],'datafiles' => []}}); $mech->get_ok('http://localhost:3010/brapi/v2/studies/139'); $response = decode_json $mech->content; print STDERR Dumper $response; -is_deeply($response, {'metadata' => {'pagination' => {'totalCount' => 1,'totalPages' => 1,'currentPage' => 0,'pageSize' => 10},'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=10'},{'message' => 'Loading CXGN::BrAPI::v2::Studies','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Studies search result constructed'}],'datafiles' => []},'result' => {'studyCode' => undef,'trialDbId' => '134','environmentParameters' => undef,'externalReferences' => undef,'dataLinks' => [],'commonCropName' => 'Cassava','studyType' => 'Clonal Evaluation','additionalInfo' => {'programDbId' => '134', 'programName' => 'test'},'documentationURL' => '','endDate' => undef,'studyDescription' => 'This trial was loaded into the fixture to test solgs.','studyName' => 'Kasese solgs trial','locationName' => 'test_location','studyPUI' => undef,'lastUpdate' => undef,'experimentalDesign' => {'PUI' => undef,'description' => 'Alpha'},'observationUnitsDescription' => undef,'startDate' => undef,'studyDbId' => '139','observationLevels' => undef,'culturalPractices' => undef,'growthFacility' => undef,'locationDbId' => '23','seasons' => ['2014'],'contacts' => undef,'active' => JSON::true ,'trialName' => 'test','license' => ''}} ); +is_deeply($response, {'metadata' => {'pagination' => {'totalCount' => 1,'totalPages' => 1,'currentPage' => 0,'pageSize' => 10},'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=10'},{'message' => 'Loading CXGN::BrAPI::v2::Studies','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Studies search result constructed'}],'datafiles' => []},'result' => {'studyCode' => undef,'trialDbId' => '134','environmentParameters' => undef,'externalReferences' => undef,'dataLinks' => [],'commonCropName' => 'Cassava','studyType' => 'Clonal Evaluation','additionalInfo' => {'programDbId' => '134', 'programName' => 'test'},'documentationURL' => '','endDate' => undef,'studyDescription' => 'This trial was loaded into the fixture to test solgs.','studyName' => 'Kasese solgs trial','locationName' => 'test_location','studyPUI' => undef,'lastUpdate' => undef,'experimentalDesign' => {'PUI' => 'Alpha','description' => 'Alpha'},'observationUnitsDescription' => undef,'startDate' => undef,'studyDbId' => '139','observationLevels' => undef,'culturalPractices' => undef,'growthFacility' => undef,'locationDbId' => '23','seasons' => ['2014'],'contacts' => undef,'active' => JSON::true ,'trialName' => 'test','license' => ''}} ); $mech->get_ok('http://localhost:3010/brapi/v2/locations?pageSize=3'); $response = decode_json $mech->content; @@ -461,20 +461,20 @@ $data = '[ { "active": "true", "additionalInfo": {}, "commonCropName": "Grape", $mech->post('http://localhost:3010/brapi/v2/studies', Content => $data); $response = decode_json $mech->content; print STDERR Dumper $response; -is_deeply($response, {'result' => {'data' => [{'observationLevels' => undef,'dataLinks' => [],'experimentalDesign' => {'PUI' => undef,'description' => 'RCBD'},'observationUnitsDescription' => undef,'studyName' => 'Observation at Kenya 1','startDate' => undef,'growthFacility' => undef,'active' => JSON::true,'lastUpdate' => undef,'contacts' => undef,'endDate' => undef,'studyDbId' => '169','locationDbId' => '23','documentationURL' => '','additionalInfo' => {'programDbId' => '134','programName' => 'test'},'seasons' => ['2018'],'culturalPractices' => undef,'studyDescription' => 'This is a yield study for Spring 2018','externalReferences' => undef,'studyPUI' => undef,'commonCropName' => 'Cassava','trialDbId' => '168','studyType' => 'phenotyping_trial','trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location','license' => '','studyCode' => undef,'environmentParameters' => undef}]},'metadata' => {'datafiles' => [],'pagination' => {'totalCount' => 1,'currentPage' => 0,'pageSize' => 10,'totalPages' => 1},'status' => [{'message' => 'BrAPI base call found with page=0, pageSize=10','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'message' => 'Studies stored successfully','messageType' => 'INFO'}]}} ); +is_deeply($response, {'result' => {'data' => [{'observationLevels' => undef,'dataLinks' => [],'experimentalDesign' => {'PUI' => 'RCBD','description' => 'RCBD'},'observationUnitsDescription' => undef,'studyName' => 'Observation at Kenya 1','startDate' => undef,'growthFacility' => undef,'active' => JSON::true,'lastUpdate' => undef,'contacts' => undef,'endDate' => undef,'studyDbId' => '169','locationDbId' => '23','documentationURL' => '','additionalInfo' => {'programDbId' => '134','programName' => 'test'},'seasons' => ['2018'],'culturalPractices' => undef,'studyDescription' => 'This is a yield study for Spring 2018','externalReferences' => undef,'studyPUI' => undef,'commonCropName' => 'Cassava','trialDbId' => '168','studyType' => 'phenotyping_trial','trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location','license' => '','studyCode' => undef,'environmentParameters' => undef}]},'metadata' => {'datafiles' => [],'pagination' => {'totalCount' => 1,'currentPage' => 0,'pageSize' => 10,'totalPages' => 1},'status' => [{'message' => 'BrAPI base call found with page=0, pageSize=10','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'message' => 'Studies stored successfully','messageType' => 'INFO'}]}} ); $data = '{ "active": "true", "additionalInfo": {}, "commonCropName": "Grape", "contacts": [], "culturalPractices": "Irrigation was applied according needs during summer to prevent water stress.", "dataLinks": [], "documentationURL": "http://breedbase.org", "endDate": "2018-01-01", "environmentParameters": [ { "description": "the soil type was clay", "parameterName": "soil type", "parameterPUI": "PECO:0007155", "unit": "pH", "unitPUI": "PECO:0007059", "value": "clay soil", "valuePUI": "ENVO:00002262" } ], "experimentalDesign": { "PUI": "CO_715:0000145", "description": "Lines were repeated twice at each location using a complete block design. In order to limit competition effects, each block was organized into four sub-blocks corresponding to earliest groups based on a prior information." }, "externalReferences": [], "growthFacility": { "PUI": "CO_715:0000162", "description": "field environment condition, greenhouse" }, "lastUpdate": { "timestamp": "2018-01-01T14:47:23-0600", "version": "1.2.3" }, "license": "MIT License", "locationDbId": "23", "locationName": "test_location", "observationLevels": [], "observationUnitsDescription": "Observation units consisted in individual plots themselves consisting of a row of 15 plants at a density of approximately six plants per square meter.", "seasons": [ "Spring_2018" ], "startDate": "2018-01-01", "studyCode": "Grape_Yield_Spring_2018", "studyDescription": "This is a yield study for Spring 2018", "studyName": "INRAs Walnut Genetic Resources Observation at Kenya modified", "studyPUI": "doi:10.155454/12349537312", "studyType": "phenotyping_trial", "trialDbId": "168", "trialName": "Peru Yield Trial 2010"}'; $resp = $ua->put("http://localhost:3010/brapi/v2/studies/139", Content => $data); $response = decode_json $resp->{_content}; print STDERR Dumper $response; -is_deeply($response, {'result' => {'culturalPractices' => undef,'studyDescription' => 'This is a yield study for Spring 2018','externalReferences' => undef,'studyPUI' => undef,'commonCropName' => 'Cassava','trialDbId' => '168','studyType' => 'phenotyping_trial','additionalInfo' => {'programName' => 'test','programDbId' => '134'},'seasons' => ['Spring_2018'],'environmentParameters' => undef,'trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location','studyCode' => undef,'license' => '','observationUnitsDescription' => undef,'studyName' => 'INRAs Walnut Genetic Resources Observation at Kenya modified','startDate' => '2018-01-01','growthFacility' => undef,'active' => JSON::true,'lastUpdate' => undef,'observationLevels' => undef,'dataLinks' => [],'experimentalDesign' => {'PUI' => undef,'description' => 'CO_715:0000145'},'locationDbId' => '23','documentationURL' => '','contacts' => undef,'endDate' => '2018-01-01','studyDbId' => '139'},'metadata' => {'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=10'},{'message' => 'Loading CXGN::BrAPI::v2::Studies','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Studies result constructed'}],'datafiles' => [],'pagination' => {'totalCount' => 1,'totalPages' => 1,'pageSize' => 10,'currentPage' => 0}}} ); +is_deeply($response, {'result' => {'culturalPractices' => undef,'studyDescription' => 'This is a yield study for Spring 2018','externalReferences' => undef,'studyPUI' => undef,'commonCropName' => 'Cassava','trialDbId' => '168','studyType' => 'phenotyping_trial','additionalInfo' => {'programName' => 'test','programDbId' => '134'},'seasons' => ['Spring_2018'],'environmentParameters' => undef,'trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location','studyCode' => undef,'license' => '','observationUnitsDescription' => undef,'studyName' => 'INRAs Walnut Genetic Resources Observation at Kenya modified','startDate' => '2018-01-01','growthFacility' => undef,'active' => JSON::true,'lastUpdate' => undef,'observationLevels' => undef,'dataLinks' => [],'experimentalDesign' => {'PUI' => 'CO_715:0000145','description' => 'CO_715:0000145'},'locationDbId' => '23','documentationURL' => '','contacts' => undef,'endDate' => '2018-01-01','studyDbId' => '139'},'metadata' => {'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=10'},{'message' => 'Loading CXGN::BrAPI::v2::Studies','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Studies result constructed'}],'datafiles' => [],'pagination' => {'totalCount' => 1,'totalPages' => 1,'pageSize' => 10,'currentPage' => 0}}} ); # -$data = '{ "studyName": "Kasese solgs trial", "trialDbId": "139", "seasons": [ "2014" ], "locationDbId":"23", "studyType":"phenotyping_trial"}'; +$data = '{ "studyName": "Kasese solgs trial", "trialDbId": "139", "seasons": [ "2014" ], "locationDbId":"23", "studyType":"phenotyping_trial", "experimentalDesign": {"PUI": "CO_715:0000145"}}'; $resp = $ua->put("http://localhost:3010/brapi/v2/studies/139", Content => $data); $response = decode_json $resp->{_content}; print STDERR Dumper $response; -is_deeply($response, {'result' => {'lastUpdate' => undef,'startDate' => '2018-01-01','active' => JSON::true,'growthFacility' => undef,'observationUnitsDescription' => undef,'studyName' => 'Kasese solgs trial','dataLinks' => [],'experimentalDesign' => {'PUI' => undef,'description' => 'CO_715:0000145'},'observationLevels' => undef,'documentationURL' => '','locationDbId' => '23','studyDbId' => '139','endDate' => '2018-01-01','contacts' => undef,'commonCropName' => 'Cassava','studyType' => 'phenotyping_trial','trialDbId' => '168','externalReferences' => undef,'studyPUI' => undef,'studyDescription' => 'This is a yield study for Spring 2018','culturalPractices' => undef,'seasons' => ['2014'],'additionalInfo' => {'programName' => 'test','programDbId' => '134'},'environmentParameters' => undef,'studyCode' => undef,'license' => '','trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location'},'metadata' => {'pagination' => {'pageSize' => 10,'currentPage' => 0,'totalPages' => 1,'totalCount' => 1},'datafiles' => [],'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=10'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'messageType' => 'INFO','message' => 'Studies result constructed'}]}}); +is_deeply($response, {'result' => {'lastUpdate' => undef,'startDate' => '2018-01-01','active' => JSON::true,'growthFacility' => undef,'observationUnitsDescription' => undef,'studyName' => 'Kasese solgs trial','dataLinks' => [],'experimentalDesign' => {'PUI' => 'CO_715:0000145','description' => 'CO_715:0000145'},'observationLevels' => undef,'documentationURL' => '','locationDbId' => '23','studyDbId' => '139','endDate' => '2018-01-01','contacts' => undef,'commonCropName' => 'Cassava','studyType' => 'phenotyping_trial','trialDbId' => '168','externalReferences' => undef,'studyPUI' => undef,'studyDescription' => 'This is a yield study for Spring 2018','culturalPractices' => undef,'seasons' => ['2014'],'additionalInfo' => {'programName' => 'test','programDbId' => '134'},'environmentParameters' => undef,'studyCode' => undef,'license' => '','trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location'},'metadata' => {'pagination' => {'pageSize' => 10,'currentPage' => 0,'totalPages' => 1,'totalCount' => 1},'datafiles' => [],'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=10'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'messageType' => 'INFO','message' => 'Studies result constructed'}]}}); $data = '{ "41782": { "observationUnitName":"CASS_6Genotypes_201", "studyDbId": "169","studyName": "Observation at Kenya 1", "germplasmDbId": "41280", "germplasmName": "TMEB693", "externalReferences" :[], "observationUnitPosition": {"entryType": "TEST", "geoCoordinates": { "geometry": { "coordinates": [ -76.506042, 42.417373, 10 ], "type": "Point" }, "type": "Feature" }, "observationLevel": { "levelName": "plot", "levelOrder": 2, "levelCode": "Plot_123" }, "observationLevelRelationships": [ { "levelCode": "Field_1", "levelName": "field", "levelOrder": 0 }, { "levelCode": "Block_12", "levelName": "block", "levelOrder": 1 }, { "levelCode": "Plot_123", "levelName": "plot", "levelOrder": 2 } ], "positionCoordinateX": "74", "positionCoordinateXType": "GRID_COL", "positionCoordinateY": "03", "positionCoordinateYType": "GRID_ROW" } }, "41301":{ "externalReferences" :[], "observationUnitPosition": {"entryType": "TEST", "geoCoordinates": { "geometry": { "coordinates": [ -76.506042, 42.417373, 20 ], "type": "Point" }, "type": "Feature" }, "observationLevel": { "levelName": "plot", "levelOrder": 2, "levelCode": "Plot_123" }, "observationLevelRelationships": [ { "levelCode": "Field_1", "levelName": "field", "levelOrder": 0 }, { "levelCode": "Block_12", "levelName": "block", "levelOrder": 1 }, { "levelCode": "Plot_123", "levelName": "plot", "levelOrder": 2 } ], "positionCoordinateX": "74", "positionCoordinateXType": "GRID_COL", "positionCoordinateY": "03", "positionCoordinateYType": "GRID_ROW" } }}'; From 0853d1af5c184ed91a6abc6f36d3d63897f85ca8 Mon Sep 17 00:00:00 2001 From: Chris T Date: Wed, 2 Jun 2021 14:44:02 -0400 Subject: [PATCH 12/14] fix misc trial type db patch script --- db/00139/AddMiscellaneousTrialType.pm | 3 +-- t/unit_mech/AJAX/BrAPI_v2.t | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/db/00139/AddMiscellaneousTrialType.pm b/db/00139/AddMiscellaneousTrialType.pm index fc20683d86..55b043e1df 100644 --- a/db/00139/AddMiscellaneousTrialType.pm +++ b/db/00139/AddMiscellaneousTrialType.pm @@ -57,11 +57,10 @@ sub patch { print STDOUT "\nChecking if this db_patch was executed before or if previous db_patches have been executed.\n"; print STDOUT "\nExecuting the SQL commands.\n"; + my $schema = Bio::Chado::Schema->connect( sub { $self->dbh->clone } ); my $coderef = sub { - my $schema = Bio::Chado::Schema->connect( sub { $self->dbh->clone } ); - my $new_cvterm = $schema->resultset("Cv::Cvterm")->create_with( { name => 'misc_trial', diff --git a/t/unit_mech/AJAX/BrAPI_v2.t b/t/unit_mech/AJAX/BrAPI_v2.t index 087390264c..e1fbb51081 100644 --- a/t/unit_mech/AJAX/BrAPI_v2.t +++ b/t/unit_mech/AJAX/BrAPI_v2.t @@ -457,11 +457,11 @@ $response = decode_json $mech->content; print STDERR Dumper $response; is_deeply($response, { 'result'=> { 'data'=> [ { 'datasetAuthorships'=> undef, 'additionalInfo'=> {}, 'publications'=> undef, 'externalReferences'=> undef, 'trialDescription'=> 'General drought resistance trial initiated in Peru', 'programDbId'=> '134', 'active'=> JSON::true, 'endDate'=> undef, 'programName'=> 'test', 'contacts'=> undef, 'documentationURL'=> undef, 'trialDbId'=> '168', 'commonCropName'=> 'Cassava', 'startDate'=> undef, 'trialPUI'=> undef, 'trialName'=> 'Peru Yield Trial 2010' } ] }, 'metadata'=> { 'pagination'=> { 'pageSize'=> 10, 'totalPages'=> 1, 'totalCount'=> 1, 'currentPage'=> 0 }, 'datafiles'=> [], 'status'=> [ { 'messageType'=> 'INFO', 'message'=> 'BrAPI base call found with page=0, pageSize=10' }, { 'messageType'=> 'INFO', 'message'=> 'Loading CXGN::BrAPI::v2::Trials' }, { 'message'=> 'Trials result constructed', 'messageType'=> 'INFO' } ] } }); -$data = '[ { "active": "true", "additionalInfo": {}, "commonCropName": "Grape", "contacts": [], "culturalPractices": "Irrigation was applied according needs during summer to prevent water stress.", "dataLinks": [], "documentationURL": "https://breedbase.org/", "endDate": "2020-06-12T22:05:35.680Z", "environmentParameters": [], "experimentalDesign": { "PUI": "RCBD", "description": "Random" }, "externalReferences": [], "growthFacility": { }, "lastUpdate": {}, "license": "MIT License", "locationDbId": "23", "locationName": "test_location", "observationLevels": [], "observationUnitsDescription": "Observation units", "seasons": [ "2018" ], "startDate": "2020-06-12T22:05:35.680Z", "studyCode": "Grape_Yield_Spring_2018", "studyDescription": "This is a yield study for Spring 2018", "studyName": "Observation at Kenya 1", "studyPUI": "doi:10.155454/12349537312", "studyType": "phenotyping_trial", "trialDbId": "168", "trialName": "Peru Yield Trial 2010"} ]'; +$data = '[ { "active": "true", "additionalInfo": {}, "commonCropName": "Grape", "contacts": [], "culturalPractices": "Irrigation was applied according needs during summer to prevent water stress.", "dataLinks": [], "documentationURL": "https://breedbase.org/", "endDate": "2020-06-12T22:05:35.680Z", "environmentParameters": [], "experimentalDesign": { "PUI": "RCBD", "description": "Random" }, "externalReferences": [], "growthFacility": { }, "lastUpdate": {}, "license": "MIT License", "locationDbId": "23", "locationName": "test_location", "observationLevels": [], "observationUnitsDescription": "Observation units", "seasons": [ "2018" ], "startDate": "2020-06-12T22:05:35.680Z", "studyCode": "Grape_Yield_Spring_2018", "studyDescription": "This is a yield study for Spring 2018", "studyName": "Observation at Kenya 1", "studyPUI": "doi:10.155454/12349537312", "studyType": "nonexisting_type", "trialDbId": "168", "trialName": "Peru Yield Trial 2010"} ]'; $mech->post('http://localhost:3010/brapi/v2/studies', Content => $data); $response = decode_json $mech->content; print STDERR Dumper $response; -is_deeply($response, {'result' => {'data' => [{'observationLevels' => undef,'dataLinks' => [],'experimentalDesign' => {'PUI' => 'RCBD','description' => 'RCBD'},'observationUnitsDescription' => undef,'studyName' => 'Observation at Kenya 1','startDate' => undef,'growthFacility' => undef,'active' => JSON::true,'lastUpdate' => undef,'contacts' => undef,'endDate' => undef,'studyDbId' => '169','locationDbId' => '23','documentationURL' => '','additionalInfo' => {'programDbId' => '134','programName' => 'test'},'seasons' => ['2018'],'culturalPractices' => undef,'studyDescription' => 'This is a yield study for Spring 2018','externalReferences' => undef,'studyPUI' => undef,'commonCropName' => 'Cassava','trialDbId' => '168','studyType' => 'phenotyping_trial','trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location','license' => '','studyCode' => undef,'environmentParameters' => undef}]},'metadata' => {'datafiles' => [],'pagination' => {'totalCount' => 1,'currentPage' => 0,'pageSize' => 10,'totalPages' => 1},'status' => [{'message' => 'BrAPI base call found with page=0, pageSize=10','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'message' => 'Studies stored successfully','messageType' => 'INFO'}]}} ); +is_deeply($response, {'result' => {'data' => [{'observationLevels' => undef,'dataLinks' => [],'experimentalDesign' => {'PUI' => 'RCBD','description' => 'RCBD'},'observationUnitsDescription' => undef,'studyName' => 'Observation at Kenya 1','startDate' => undef,'growthFacility' => undef,'active' => JSON::true,'lastUpdate' => undef,'contacts' => undef,'endDate' => undef,'studyDbId' => '169','locationDbId' => '23','documentationURL' => '','additionalInfo' => {'programDbId' => '134','programName' => 'test'},'seasons' => ['2018'],'culturalPractices' => undef,'studyDescription' => 'This is a yield study for Spring 2018','externalReferences' => undef,'studyPUI' => undef,'commonCropName' => 'Cassava','trialDbId' => '168','studyType' => 'nonexisting_type','trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location','license' => '','studyCode' => undef,'environmentParameters' => undef}]},'metadata' => {'datafiles' => [],'pagination' => {'totalCount' => 1,'currentPage' => 0,'pageSize' => 10,'totalPages' => 1},'status' => [{'message' => 'BrAPI base call found with page=0, pageSize=10','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'message' => 'Studies stored successfully','messageType' => 'INFO'}]}} ); $data = '{ "active": "true", "additionalInfo": {}, "commonCropName": "Grape", "contacts": [], "culturalPractices": "Irrigation was applied according needs during summer to prevent water stress.", "dataLinks": [], "documentationURL": "http://breedbase.org", "endDate": "2018-01-01", "environmentParameters": [ { "description": "the soil type was clay", "parameterName": "soil type", "parameterPUI": "PECO:0007155", "unit": "pH", "unitPUI": "PECO:0007059", "value": "clay soil", "valuePUI": "ENVO:00002262" } ], "experimentalDesign": { "PUI": "CO_715:0000145", "description": "Lines were repeated twice at each location using a complete block design. In order to limit competition effects, each block was organized into four sub-blocks corresponding to earliest groups based on a prior information." }, "externalReferences": [], "growthFacility": { "PUI": "CO_715:0000162", "description": "field environment condition, greenhouse" }, "lastUpdate": { "timestamp": "2018-01-01T14:47:23-0600", "version": "1.2.3" }, "license": "MIT License", "locationDbId": "23", "locationName": "test_location", "observationLevels": [], "observationUnitsDescription": "Observation units consisted in individual plots themselves consisting of a row of 15 plants at a density of approximately six plants per square meter.", "seasons": [ "Spring_2018" ], "startDate": "2018-01-01", "studyCode": "Grape_Yield_Spring_2018", "studyDescription": "This is a yield study for Spring 2018", "studyName": "INRAs Walnut Genetic Resources Observation at Kenya modified", "studyPUI": "doi:10.155454/12349537312", "studyType": "phenotyping_trial", "trialDbId": "168", "trialName": "Peru Yield Trial 2010"}'; $resp = $ua->put("http://localhost:3010/brapi/v2/studies/139", Content => $data); From b7efb673cc7d1c4c0af16197a713d0466c39be5c Mon Sep 17 00:00:00 2001 From: Chris T Date: Wed, 16 Jun 2021 10:08:24 -0400 Subject: [PATCH 13/14] add study design method check on POST, PUT brapi studies --- lib/CXGN/BrAPI/v2/Studies.pm | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/CXGN/BrAPI/v2/Studies.pm b/lib/CXGN/BrAPI/v2/Studies.pm index 10328f4148..f5079f37cd 100644 --- a/lib/CXGN/BrAPI/v2/Studies.pm +++ b/lib/CXGN/BrAPI/v2/Studies.pm @@ -190,6 +190,12 @@ sub store { } } + # Check that a supported study design type was passed + my %supported_methods = map { $_ => 1 } ("CRD","Alpha","MAD","Lattice","Augmented","RCBD","p-rep","splitplot","greenhouse","Westcott","Analysis"); + if (!exists($supported_methods{$trial_design_method})) { + return CXGN::BrAPI::JSONResponse->return_error($self->status, "Experimental Design, $trial_design_method, must be one of the following: 'CRD','Alpha','MAD','Lattice','Augmented','RCBD','p-rep','splitplot','greenhouse','Westcott','Analysis'.", 400); + } + # Check the trial exists my $brapi_trial = $self->bcs_schema()->resultset('Project::Project')->find( { project_id=>$folder_id }); if (! defined $brapi_trial) { @@ -391,6 +397,12 @@ sub update { my $planting_date = $params->{startDate} ? $params->{startDate} : undef; my $harvest_date = $params->{endDate} ? $params->{endDate} : undef; + # Check that a supported study design type was passed + my %supported_methods = map { $_ => 1 } ("CRD","Alpha","MAD","Lattice","Augmented","RCBD","p-rep","splitplot","greenhouse","Westcott","Analysis"); + if (!exists($supported_methods{$study_design_method})) { + return CXGN::BrAPI::JSONResponse->return_error($self->status, "Experimental Design, $study_design_method, must be one of the following: 'CRD','Alpha','MAD','Lattice','Augmented','RCBD','p-rep','splitplot','greenhouse','Westcott','Analysis'.", 400); + } + # Check the brapi trial exists my $brapi_trial = $self->bcs_schema()->resultset('Project::Project')->find( { project_id=>$folder_id }); if (! defined $brapi_trial) { From 03ba0594c482b99992d8b5e0f9c5449be5252ea0 Mon Sep 17 00:00:00 2001 From: Chris T Date: Wed, 16 Jun 2021 10:44:22 -0400 Subject: [PATCH 14/14] brapi studies test fixes --- t/unit_mech/AJAX/BrAPI_v2.t | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t/unit_mech/AJAX/BrAPI_v2.t b/t/unit_mech/AJAX/BrAPI_v2.t index e1fbb51081..f34fc84c5d 100644 --- a/t/unit_mech/AJAX/BrAPI_v2.t +++ b/t/unit_mech/AJAX/BrAPI_v2.t @@ -463,18 +463,18 @@ $response = decode_json $mech->content; print STDERR Dumper $response; is_deeply($response, {'result' => {'data' => [{'observationLevels' => undef,'dataLinks' => [],'experimentalDesign' => {'PUI' => 'RCBD','description' => 'RCBD'},'observationUnitsDescription' => undef,'studyName' => 'Observation at Kenya 1','startDate' => undef,'growthFacility' => undef,'active' => JSON::true,'lastUpdate' => undef,'contacts' => undef,'endDate' => undef,'studyDbId' => '169','locationDbId' => '23','documentationURL' => '','additionalInfo' => {'programDbId' => '134','programName' => 'test'},'seasons' => ['2018'],'culturalPractices' => undef,'studyDescription' => 'This is a yield study for Spring 2018','externalReferences' => undef,'studyPUI' => undef,'commonCropName' => 'Cassava','trialDbId' => '168','studyType' => 'nonexisting_type','trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location','license' => '','studyCode' => undef,'environmentParameters' => undef}]},'metadata' => {'datafiles' => [],'pagination' => {'totalCount' => 1,'currentPage' => 0,'pageSize' => 10,'totalPages' => 1},'status' => [{'message' => 'BrAPI base call found with page=0, pageSize=10','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'message' => 'Studies stored successfully','messageType' => 'INFO'}]}} ); -$data = '{ "active": "true", "additionalInfo": {}, "commonCropName": "Grape", "contacts": [], "culturalPractices": "Irrigation was applied according needs during summer to prevent water stress.", "dataLinks": [], "documentationURL": "http://breedbase.org", "endDate": "2018-01-01", "environmentParameters": [ { "description": "the soil type was clay", "parameterName": "soil type", "parameterPUI": "PECO:0007155", "unit": "pH", "unitPUI": "PECO:0007059", "value": "clay soil", "valuePUI": "ENVO:00002262" } ], "experimentalDesign": { "PUI": "CO_715:0000145", "description": "Lines were repeated twice at each location using a complete block design. In order to limit competition effects, each block was organized into four sub-blocks corresponding to earliest groups based on a prior information." }, "externalReferences": [], "growthFacility": { "PUI": "CO_715:0000162", "description": "field environment condition, greenhouse" }, "lastUpdate": { "timestamp": "2018-01-01T14:47:23-0600", "version": "1.2.3" }, "license": "MIT License", "locationDbId": "23", "locationName": "test_location", "observationLevels": [], "observationUnitsDescription": "Observation units consisted in individual plots themselves consisting of a row of 15 plants at a density of approximately six plants per square meter.", "seasons": [ "Spring_2018" ], "startDate": "2018-01-01", "studyCode": "Grape_Yield_Spring_2018", "studyDescription": "This is a yield study for Spring 2018", "studyName": "INRAs Walnut Genetic Resources Observation at Kenya modified", "studyPUI": "doi:10.155454/12349537312", "studyType": "phenotyping_trial", "trialDbId": "168", "trialName": "Peru Yield Trial 2010"}'; +$data = '{ "active": "true", "additionalInfo": {}, "commonCropName": "Grape", "contacts": [], "culturalPractices": "Irrigation was applied according needs during summer to prevent water stress.", "dataLinks": [], "documentationURL": "http://breedbase.org", "endDate": "2018-01-01", "environmentParameters": [ { "description": "the soil type was clay", "parameterName": "soil type", "parameterPUI": "PECO:0007155", "unit": "pH", "unitPUI": "PECO:0007059", "value": "clay soil", "valuePUI": "ENVO:00002262" } ], "experimentalDesign": { "PUI": "CRD", "description": "Lines were repeated twice at each location using a complete block design. In order to limit competition effects, each block was organized into four sub-blocks corresponding to earliest groups based on a prior information." }, "externalReferences": [], "growthFacility": { "PUI": "CO_715:0000162", "description": "field environment condition, greenhouse" }, "lastUpdate": { "timestamp": "2018-01-01T14:47:23-0600", "version": "1.2.3" }, "license": "MIT License", "locationDbId": "23", "locationName": "test_location", "observationLevels": [], "observationUnitsDescription": "Observation units consisted in individual plots themselves consisting of a row of 15 plants at a density of approximately six plants per square meter.", "seasons": [ "Spring_2018" ], "startDate": "2018-01-01", "studyCode": "Grape_Yield_Spring_2018", "studyDescription": "This is a yield study for Spring 2018", "studyName": "INRAs Walnut Genetic Resources Observation at Kenya modified", "studyPUI": "doi:10.155454/12349537312", "studyType": "phenotyping_trial", "trialDbId": "168", "trialName": "Peru Yield Trial 2010"}'; $resp = $ua->put("http://localhost:3010/brapi/v2/studies/139", Content => $data); $response = decode_json $resp->{_content}; print STDERR Dumper $response; -is_deeply($response, {'result' => {'culturalPractices' => undef,'studyDescription' => 'This is a yield study for Spring 2018','externalReferences' => undef,'studyPUI' => undef,'commonCropName' => 'Cassava','trialDbId' => '168','studyType' => 'phenotyping_trial','additionalInfo' => {'programName' => 'test','programDbId' => '134'},'seasons' => ['Spring_2018'],'environmentParameters' => undef,'trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location','studyCode' => undef,'license' => '','observationUnitsDescription' => undef,'studyName' => 'INRAs Walnut Genetic Resources Observation at Kenya modified','startDate' => '2018-01-01','growthFacility' => undef,'active' => JSON::true,'lastUpdate' => undef,'observationLevels' => undef,'dataLinks' => [],'experimentalDesign' => {'PUI' => 'CO_715:0000145','description' => 'CO_715:0000145'},'locationDbId' => '23','documentationURL' => '','contacts' => undef,'endDate' => '2018-01-01','studyDbId' => '139'},'metadata' => {'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=10'},{'message' => 'Loading CXGN::BrAPI::v2::Studies','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Studies result constructed'}],'datafiles' => [],'pagination' => {'totalCount' => 1,'totalPages' => 1,'pageSize' => 10,'currentPage' => 0}}} ); +is_deeply($response, {'result' => {'culturalPractices' => undef,'studyDescription' => 'This is a yield study for Spring 2018','externalReferences' => undef,'studyPUI' => undef,'commonCropName' => 'Cassava','trialDbId' => '168','studyType' => 'phenotyping_trial','additionalInfo' => {'programName' => 'test','programDbId' => '134'},'seasons' => ['Spring_2018'],'environmentParameters' => undef,'trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location','studyCode' => undef,'license' => '','observationUnitsDescription' => undef,'studyName' => 'INRAs Walnut Genetic Resources Observation at Kenya modified','startDate' => '2018-01-01','growthFacility' => undef,'active' => JSON::true,'lastUpdate' => undef,'observationLevels' => undef,'dataLinks' => [],'experimentalDesign' => {'PUI' => 'CRD','description' => 'CRD'},'locationDbId' => '23','documentationURL' => '','contacts' => undef,'endDate' => '2018-01-01','studyDbId' => '139'},'metadata' => {'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=10'},{'message' => 'Loading CXGN::BrAPI::v2::Studies','messageType' => 'INFO'},{'messageType' => 'INFO','message' => 'Studies result constructed'}],'datafiles' => [],'pagination' => {'totalCount' => 1,'totalPages' => 1,'pageSize' => 10,'currentPage' => 0}}} ); # -$data = '{ "studyName": "Kasese solgs trial", "trialDbId": "139", "seasons": [ "2014" ], "locationDbId":"23", "studyType":"phenotyping_trial", "experimentalDesign": {"PUI": "CO_715:0000145"}}'; +$data = '{ "studyName": "Kasese solgs trial", "trialDbId": "168", "seasons": [ "2014" ], "locationDbId":"23", "studyType":"phenotyping_trial", "experimentalDesign": {"PUI": "CRD"}}'; $resp = $ua->put("http://localhost:3010/brapi/v2/studies/139", Content => $data); $response = decode_json $resp->{_content}; print STDERR Dumper $response; -is_deeply($response, {'result' => {'lastUpdate' => undef,'startDate' => '2018-01-01','active' => JSON::true,'growthFacility' => undef,'observationUnitsDescription' => undef,'studyName' => 'Kasese solgs trial','dataLinks' => [],'experimentalDesign' => {'PUI' => 'CO_715:0000145','description' => 'CO_715:0000145'},'observationLevels' => undef,'documentationURL' => '','locationDbId' => '23','studyDbId' => '139','endDate' => '2018-01-01','contacts' => undef,'commonCropName' => 'Cassava','studyType' => 'phenotyping_trial','trialDbId' => '168','externalReferences' => undef,'studyPUI' => undef,'studyDescription' => 'This is a yield study for Spring 2018','culturalPractices' => undef,'seasons' => ['2014'],'additionalInfo' => {'programName' => 'test','programDbId' => '134'},'environmentParameters' => undef,'studyCode' => undef,'license' => '','trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location'},'metadata' => {'pagination' => {'pageSize' => 10,'currentPage' => 0,'totalPages' => 1,'totalCount' => 1},'datafiles' => [],'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=10'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'messageType' => 'INFO','message' => 'Studies result constructed'}]}}); +is_deeply($response, {'result' => {'lastUpdate' => undef,'startDate' => '2018-01-01','active' => JSON::true,'growthFacility' => undef,'observationUnitsDescription' => undef,'studyName' => 'Kasese solgs trial','dataLinks' => [],'experimentalDesign' => {'PUI' => 'CRD','description' => 'CRD'},'observationLevels' => undef,'documentationURL' => '','locationDbId' => '23','studyDbId' => '139','endDate' => '2018-01-01','contacts' => undef,'commonCropName' => 'Cassava','studyType' => 'phenotyping_trial','trialDbId' => '168','externalReferences' => undef,'studyPUI' => undef,'studyDescription' => 'This is a yield study for Spring 2018','culturalPractices' => undef,'seasons' => ['2014'],'additionalInfo' => {'programName' => 'test','programDbId' => '134'},'environmentParameters' => undef,'studyCode' => undef,'license' => '','trialName' => 'Peru Yield Trial 2010','locationName' => 'test_location'},'metadata' => {'pagination' => {'pageSize' => 10,'currentPage' => 0,'totalPages' => 1,'totalCount' => 1},'datafiles' => [],'status' => [{'messageType' => 'INFO','message' => 'BrAPI base call found with page=0, pageSize=10'},{'messageType' => 'INFO','message' => 'Loading CXGN::BrAPI::v2::Studies'},{'messageType' => 'INFO','message' => 'Studies result constructed'}]}}); $data = '{ "41782": { "observationUnitName":"CASS_6Genotypes_201", "studyDbId": "169","studyName": "Observation at Kenya 1", "germplasmDbId": "41280", "germplasmName": "TMEB693", "externalReferences" :[], "observationUnitPosition": {"entryType": "TEST", "geoCoordinates": { "geometry": { "coordinates": [ -76.506042, 42.417373, 10 ], "type": "Point" }, "type": "Feature" }, "observationLevel": { "levelName": "plot", "levelOrder": 2, "levelCode": "Plot_123" }, "observationLevelRelationships": [ { "levelCode": "Field_1", "levelName": "field", "levelOrder": 0 }, { "levelCode": "Block_12", "levelName": "block", "levelOrder": 1 }, { "levelCode": "Plot_123", "levelName": "plot", "levelOrder": 2 } ], "positionCoordinateX": "74", "positionCoordinateXType": "GRID_COL", "positionCoordinateY": "03", "positionCoordinateYType": "GRID_ROW" } }, "41301":{ "externalReferences" :[], "observationUnitPosition": {"entryType": "TEST", "geoCoordinates": { "geometry": { "coordinates": [ -76.506042, 42.417373, 20 ], "type": "Point" }, "type": "Feature" }, "observationLevel": { "levelName": "plot", "levelOrder": 2, "levelCode": "Plot_123" }, "observationLevelRelationships": [ { "levelCode": "Field_1", "levelName": "field", "levelOrder": 0 }, { "levelCode": "Block_12", "levelName": "block", "levelOrder": 1 }, { "levelCode": "Plot_123", "levelName": "plot", "levelOrder": 2 } ], "positionCoordinateX": "74", "positionCoordinateXType": "GRID_COL", "positionCoordinateY": "03", "positionCoordinateYType": "GRID_ROW" } }}';