Added eval; site now shows clean dataset missing message instead of server error...
[sgn.git] / lib / SGN / Controller / AJAX / Trial.pm
blob1f5557209e9df13d78d6a04077542be07745e489
2 =head1 NAME
4 SGN::Controller::AJAX::Trial - a REST controller class to provide the
5 backend for adding trials and viewing trials
7 =head1 DESCRIPTION
9 Creating, viewing and deleting trials
11 =head1 AUTHOR
13 Jeremy Edwards <jde22@cornell.edu>
16 =cut
18 package SGN::Controller::AJAX::Trial;
20 use Moose;
21 use utf8;
22 use Try::Tiny;
23 use Scalar::Util qw(looks_like_number);
24 use DateTime;
25 use File::Basename qw | basename dirname|;
26 use File::Copy;
27 use File::Slurp;
28 use File::Spec::Functions;
29 use Digest::MD5;
30 use List::MoreUtils qw /any /;
31 use Data::Dumper;
32 use CXGN::Trial;
33 use CXGN::Trial::TrialDesign;
34 use CXGN::Trial::TrialCreate;
35 use SGN::View::Trial qw/design_layout_view design_info_view design_layout_map_view/;
36 use CXGN::Location::LocationLookup;
37 use CXGN::Stock::StockLookup;
38 use CXGN::Trial::TrialLayout;
39 use CXGN::BreedersToolbox::Projects;
40 use CXGN::BreedersToolbox::Delete;
41 use CXGN::UploadFile;
42 use CXGN::Trial::ParseUpload;
43 use CXGN::List::Transform;
44 use CXGN::List::Validate;
45 use SGN::Model::Cvterm;
46 use JSON::XS;
47 use CXGN::BreedersToolbox::Accessions;
48 use CXGN::BreederSearch;
49 use YAML;
50 use CXGN::TrialStatus;
51 use CXGN::Calendar;
52 use CXGN::BreedersToolbox::SoilData;
53 use CXGN::Contact;
54 use CXGN::File::Parse;
55 use CXGN::People::Person;
56 use CXGN::Tools::Run;
58 BEGIN { extends 'Catalyst::Controller::REST' }
60 __PACKAGE__->config(
61 default => 'application/json',
62 stash_key => 'rest',
63 map => { 'application/json' => 'JSON', 'text/html' => 'JSON' },
66 has 'schema' => (
67 is => 'rw',
68 isa => 'DBIx::Class::Schema',
69 lazy_build => 1,
73 sub generate_experimental_design : Path('/ajax/trial/generate_experimental_design') : ActionClass('REST') { }
75 sub generate_experimental_design_POST : Args(0) {
76 my ($self, $c) = @_;
77 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
78 my $trial_design = CXGN::Trial::TrialDesign->new();
79 my %design;
80 my %design_info;
81 my $error;
82 my $project_name = $c->req->param('project_name');
83 my $project_description = $c->req->param('project_description');
84 my $year = $c->req->param('year');
85 my $trial_stock_type = $c->req->param('trial_stock_type');
86 my @stock_names;
87 my $design_layout_view_html;
88 my $design_info_view_html;
89 my $design_map_view;
91 my $plot_numbering_scheme = $c->req->param('plot_numbering_scheme') || 'block_based';
92 print STDERR "Setting plot_numbering_scheme to $plot_numbering_scheme\n";
93 $trial_design->set_plot_numbering_scheme($plot_numbering_scheme);
95 if ($c->req->param('stock_list')) {
96 @stock_names = @{_parse_list_from_json($c->req->param('stock_list'))};
98 my $seedlot_hash_json = $c->req->param('seedlot_hash');
99 my @control_names;
100 if ($c->req->param('control_list')) {
101 @control_names = @{_parse_list_from_json($c->req->param('control_list'))};
104 my @control_names_crbd;
105 if ($c->req->param('control_list_crbd')) {
106 @control_names_crbd = @{_parse_list_from_json($c->req->param('control_list_crbd'))};
109 my $design_type = $c->req->param('design_type');
110 my $rep_count = $c->req->param('rep_count');
111 my $block_number = $c->req->param('block_number');
113 my $row_number = $c->req->param('row_number');
114 my $block_row_number=$c->req->param('row_number_per_block');
115 my $block_col_number=$c->req->param('col_number_per_block');
116 my $col_number =$c->req->param('col_number');
118 my $block_size = $c->req->param('block_size');
119 my $max_block_size = $c->req->param('max_block_size');
120 my $plot_prefix = $c->req->param('plot_prefix');
121 my $start_number = $c->req->param('start_number');
122 my $plot_numbering_scheme = $c->req->param('plot_numbering_scheme');
123 my $increment = $c->req->param('increment') ? $c->req->param('increment') : 1;
124 my $trial_location = $c->req->param('trial_location');
125 my $fieldmap_col_number = $c->req->param('fieldmap_col_number');
126 my $fieldmap_row_number = $c->req->param('fieldmap_row_number');
127 my $plot_layout_format = $c->req->param('plot_layout_format');
128 my @treatments = $c->req->param('treatments[]');
129 my $num_plants_per_plot = $c->req->param('num_plants_per_plot');
130 my $num_seed_per_plot = $c->req->param('num_seed_per_plot');
131 my $westcott_check_1 = $c->req->param('westcott_check_1');
132 my $westcott_check_2 = $c->req->param('westcott_check_2');
133 my $westcott_col = $c->req->param('westcott_col');
134 my $westcott_col_between_check = $c->req->param('westcott_col_between_check');
135 my $field_size = $c->req->param('field_size');
136 my $plot_width = $c->req->param('plot_width');
137 my $plot_length = $c->req->param('plot_length');
139 if ( !$start_number ) {
140 $c->stash->{rest} = { error => "You need to select the starting plot number."};
144 if ($design_type eq 'Westcott'){
145 if (!$westcott_check_1){
146 $c->stash->{rest} = { error => "You need to provide name of check 1 for westcott design."};
147 return;
149 if (!$westcott_check_2){
150 $c->stash->{rest} = { error => "You need to provide name of check 2 for westcott design."};
151 return;
153 if (!$westcott_col){
154 $c->stash->{rest} = { error => "You need to provide number of columns for westcott design."};
155 return;
157 push @control_names_crbd, $westcott_check_1;
158 push @control_names_crbd, $westcott_check_2;
161 if ($design_type eq 'splitplot'){
162 if (scalar(@treatments)<1){
163 $c->stash->{rest} = { error => "You need to provide at least one treatment for a splitplot design."};
164 return;
166 if (!$num_plants_per_plot){
167 $c->stash->{rest} = { error => "You need to provide number of plants per treatment for a splitplot design."};
168 return;
170 if ($num_plants_per_plot <1){
171 $c->stash->{rest} = { error => "You need to provide number of plants per treatment for a splitplot design."};
172 return;
176 if ($design_type eq 'RRC'){
177 if (!$fieldmap_row_number){
178 $c->stash->{rest} = { error => "You need to provide number of rows for a resolvable row-column design."};
179 return;
183 my $row_in_design_number = $c->req->param('row_in_design_number');
184 my $col_in_design_number = $c->req->param('col_in_design_number');
185 my $no_of_rep_times = $c->req->param('no_of_rep_times');
186 my $no_of_block_sequence = $c->req->param('no_of_block_sequence');
187 my $unreplicated_stock_list = $c->req->param('unreplicated_stock_list');
188 my $replicated_stock_list = $c->req->param('replicated_stock_list');
189 my $no_of_sub_block_sequence = $c->req->param('no_of_sub_block_sequence');
191 my @replicated_stocks;
192 if ($c->req->param('replicated_stock_list')) {
193 @replicated_stocks = @{_parse_list_from_json($c->req->param('replicated_stock_list'))};
195 my $number_of_replicated_stocks = scalar(@replicated_stocks);
197 my @unreplicated_stocks;
198 if ($c->req->param('unreplicated_stock_list')) {
199 @unreplicated_stocks = @{_parse_list_from_json($c->req->param('unreplicated_stock_list'))};
201 my $number_of_unreplicated_stocks = scalar(@unreplicated_stocks);
203 my $greenhouse_num_plants = $c->req->param('greenhouse_num_plants');
204 my $use_same_layout = $c->req->param('use_same_layout');
205 my $number_of_checks = scalar(@control_names_crbd);
207 if ($design_type eq "RCBD" || $design_type eq "RRC" || $design_type eq "DRRC" ||$design_type eq "Alpha" || $design_type eq "CRD" || $design_type eq "Lattice") {
208 if (@control_names_crbd) {
209 @stock_names = (@stock_names, @control_names_crbd);
213 my $number_of_prep_stocks = scalar(@stock_names);
214 my $p_rep_total_plots;
215 my $replicated_plots;
216 my $unreplicated_plots;
217 my $calculated_total_plot;
219 if($design_type eq "p-rep"){
220 @stock_names = (@replicated_stocks, @unreplicated_stocks);
223 $number_of_prep_stocks = scalar(@stock_names);
224 $p_rep_total_plots = $row_in_design_number * $col_in_design_number;
225 $replicated_plots = $no_of_rep_times * $number_of_replicated_stocks;
226 $unreplicated_plots = scalar(@unreplicated_stocks);
227 $calculated_total_plot = $replicated_plots + $unreplicated_plots;
230 my @locations;
232 try {
233 my $json = JSON::XS->new();
234 my $multi_location = $json->decode($trial_location);
235 foreach my $loc (@$multi_location) {
236 push @locations, $loc;
239 catch {
240 push @locations, $trial_location;
243 my $location_number = scalar(@locations);
245 if (!$c->user()) {
246 $c->stash->{rest} = {error => "You need to be logged in to add a trial" };
247 return;
250 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) { #user must have privileges to add a trial
251 $c->stash->{rest} = {error => "You have insufficient privileges to add a trial." };
252 return;
254 #print "TOTAL PLOTS $p_rep_total_plots AND CALCULATED PLOTS $calculated_total_plot\n";
255 if($p_rep_total_plots != $calculated_total_plot){
256 $c->stash->{rest} = {error => "Treatment repeats do not equal number of plots in design" };
257 return;
260 my @design_array;
261 my @design_layout_view_html_array;
262 my $json = JSON::XS->new();
264 foreach my $location (@locations) {
265 my $trial_name = $c->req->param('project_name');
266 my $geolocation_lookup = CXGN::Location::LocationLookup->new(schema => $schema);
268 $geolocation_lookup->set_location_name($location);
269 if (!$geolocation_lookup->get_geolocation()){
270 $c->stash->{rest} = { error => "Trial location not found" };
271 return;
274 if ($location_number > 1) {
276 # Add location abbreviation or name to trial name
277 my $location_id = $geolocation_lookup->get_geolocation()->nd_geolocation_id();
278 my $location_object = CXGN::Location->new( {
279 bcs_schema => $schema,
280 nd_geolocation_id => $location_id,
283 my $abbreviation = $location_object->abbreviation();
285 if ($abbreviation) {
286 $trial_name = $trial_name.$abbreviation;
287 } else {
288 $trial_name = $trial_name.$location;
292 #strip name of any invalid filename characters
293 $trial_name =~ s/[\\\/\s:,"*?<>|]+//;
294 $trial_design->set_trial_name($trial_name);
296 my $dir = $c->tempfiles_subdir('trial_designs');
297 my ($FH, $filename) = $c->tempfile(TEMPLATE=>"trial_designs/$design_type-XXXXX");
298 my $design_tempfile = $c->config->{basepath}.$filename;
299 # my $design_tempfile = "".$filename;
300 $trial_design->set_tempfile($design_tempfile);
301 $trial_design->set_backend($c->config->{backend});
302 $trial_design->set_submit_host($c->config->{cluster_host});
303 $trial_design->set_temp_base($c->config->{cluster_shared_tempdir});
304 $trial_design->set_plot_numbering_scheme($plot_numbering_scheme);
306 my $design_created = 0;
307 if ($use_same_layout) {
308 $design_created = 1;
311 if ($design_created) {
312 $trial_design->set_randomization_seed($design_created);
315 if (@stock_names) {
316 $trial_design->set_stock_list(\@stock_names);
317 $design_info{'number_of_stocks'} = scalar(@stock_names);
318 } else {
319 $c->stash->{rest} = {error => "No list of stocks supplied." };
320 return;
322 if ($seedlot_hash_json){
323 $trial_design->set_seedlot_hash($json->decode($seedlot_hash_json));
325 if ($num_seed_per_plot){
326 $trial_design->set_num_seed_per_plot($num_seed_per_plot);
328 if (@control_names) {
329 $trial_design->set_control_list(\@control_names);
330 $design_info{'number_of_controls'} = scalar(@control_names);
332 if (@control_names_crbd) {
333 $trial_design->set_control_list_crbd(\@control_names_crbd);
334 $design_info{'number_of_controls_crbd'} = scalar(@control_names_crbd);
336 if ($start_number) {
337 $trial_design->set_plot_start_number($start_number);
338 } else {
339 $trial_design->clear_plot_start_number();
341 if ($increment) {
342 $trial_design->set_plot_number_increment($increment);
343 } else {
344 $trial_design->clear_plot_number_increment();
346 if ($plot_prefix) {
347 $trial_design->set_plot_name_prefix($plot_prefix);
349 if ($rep_count) {
350 $trial_design->set_number_of_reps($rep_count);
352 if ($block_number) {
353 $trial_design->set_number_of_blocks($block_number);
355 if($row_number){
356 $trial_design->set_number_of_rows($row_number);
358 if($block_row_number){
359 $trial_design->set_block_row_numbers($block_row_number);
361 if($block_col_number){
362 $trial_design->set_block_col_numbers($block_col_number);
364 if($col_number){
365 $trial_design->set_number_of_cols($col_number);
367 if ($block_size) {
368 $trial_design->set_block_size($block_size);
370 if ($max_block_size) {
371 $trial_design->set_maximum_block_size($max_block_size);
373 if ($greenhouse_num_plants) {
374 my $json = JSON::XS->new();
375 $trial_design->set_greenhouse_num_plants($json->decode($greenhouse_num_plants));
377 if ($westcott_check_1){
378 $trial_design->set_westcott_check_1($westcott_check_1);
380 if ($westcott_check_2){
381 $trial_design->set_westcott_check_2($westcott_check_2);
383 if ($westcott_col){
384 $trial_design->set_westcott_col($westcott_col);
386 if ($westcott_col_between_check){
387 $trial_design->set_westcott_col_between_check($westcott_col_between_check);
389 if ($location_number) {
390 $design_info{'number_of_locations'} = $location_number;
392 if($number_of_checks){
393 $design_info{'number_of_checks'} = $number_of_checks;
395 if ($design_type) {
396 $trial_design->set_design_type($design_type);
397 $design_info{'design_type'} = $design_type;
398 } else {
399 $c->stash->{rest} = {error => "No design type supplied." };
400 return;
402 if (!$trial_design->has_design_type()) {
403 $c->stash->{rest} = {error => "Design type not supported." };
404 return;
406 if ($fieldmap_col_number) {
407 $trial_design->set_fieldmap_col_number($fieldmap_col_number);
409 if ($fieldmap_row_number) {
410 $trial_design->set_fieldmap_row_number($fieldmap_row_number);
412 if ($plot_layout_format) {
413 $trial_design->set_plot_layout_format($plot_layout_format);
415 if ($number_of_replicated_stocks) {
416 $trial_design->set_replicated_stock_no($number_of_replicated_stocks);
418 if ($number_of_unreplicated_stocks) {
419 $trial_design->set_unreplicated_stock_no($number_of_unreplicated_stocks);
421 if ($row_in_design_number) {
422 $trial_design->set_row_in_design_number($row_in_design_number);
424 if ($col_in_design_number) {
425 $trial_design->set_col_in_design_number($col_in_design_number);
427 if ($no_of_rep_times) {
428 $trial_design->set_num_of_replicated_times($no_of_rep_times);
430 if ($no_of_block_sequence) {
431 $trial_design->set_block_sequence($no_of_block_sequence);
433 if ($no_of_sub_block_sequence) {
434 $trial_design->set_sub_block_sequence($no_of_sub_block_sequence);
437 if (scalar(@treatments)>0) {
438 $trial_design->set_treatments(\@treatments);
440 if($num_plants_per_plot){
441 $trial_design->set_num_plants_per_plot($num_plants_per_plot);
444 try {
445 $trial_design->calculate_design();
446 } catch {
447 $c->stash->{rest} = {error => "Could not calculate design: $_"};
448 $error=1;
450 if ($error) {
451 return;
453 if ($trial_design->get_design()) {
454 %design = %{$trial_design->get_design()};
455 } else {
456 $c->stash->{rest} = {error => "Could not generate design" };
457 return;
460 #For printing the table view of the generated design there are two designs that are different from the others:
461 # 1. the greenhouse can use accessions or crosses, so the table should reflect that. the greenhouse generates plant and plot entries so the table should reflect that.
462 # 2. the splitplot generates plots, subplots, and plant entries, so the table should reflect that.
463 $design_layout_view_html = design_layout_view(\%design, \%design_info, $design_type, $trial_stock_type);
464 $design_map_view = design_layout_map_view(\%design, $design_type);
465 $design_info_view_html = design_info_view(\%design, \%design_info, $trial_stock_type);
466 my $design_json = $json->encode(\%design);
467 push @design_array, $design_json;
468 push @design_layout_view_html_array, $design_layout_view_html;
471 my $warning_message;
472 #check if field size can fit the design_json
473 if ($field_size && $plot_width && $plot_length){
474 my $num_plots = scalar( keys %{$json->decode($design_array[0])} );
475 my $total_area = $plot_width * $plot_length * $num_plots; #sq meters. 1 ha = 10000m2
476 my $field_size_m = $field_size * 10000;
477 if ($field_size_m < $total_area){
478 $warning_message = "The generated design would require atleast $total_area square meters, which is larger than the $field_size hectare ($field_size_m square meters) field size you indicated.";
479 } else {
480 $warning_message = "The generated design would require atleast $total_area square meters and your field size is $field_size hectare ($field_size_m square meters).";
484 $c->stash->{rest} = {
485 success => "1",
486 design_layout_view_html => $json->encode(\@design_layout_view_html_array),
487 design_info_view_html => $design_info_view_html,
488 design_map_view => $design_map_view,
489 design_json => $json->encode(\@design_array),
490 warning_message => $warning_message
494 sub test_controller : Path('ajax/trial/test_controller/') : ActionClass('REST') {
495 my $self = shift;
496 my $c = shift;
497 $c->stash->{rest} = {success => $c};
498 $c->stash->{rest} = {error => $c};
499 return $c;
502 sub save_experimental_design : Path('/ajax/trial/save_experimental_design') : ActionClass('REST') { print STDERR "went into save_experimental_design \n"; }
504 sub save_experimental_design_POST : Args(0) {
505 #$| = 1;
506 print STDERR "This message means it is printing from the subroutine save_experimental_design_POST \n";
507 my ($self, $c) = @_;
509 my $user_id = $c->user()->get_object()->get_sp_person_id();
510 print STDERR "this is sp_person_id from saving trial details: ".$user_id."\n";
511 # open my $file(STDERR "This is getting read to file: user id: ".$user_id);
513 my $chado_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $user_id);
514 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $user_id);
515 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema");
516 my $dbh = $c->dbc->dbh;
517 my $save;
519 print STDERR "Saving trial... :-)\n";
521 if (!$c->user()) {
522 $c->stash->{rest} = {error => "You need to be logged in to add a trial" };
523 return;
525 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) {
526 $c->stash->{rest} = {error => "You have insufficient privileges to add a trial." };
527 return;
531 my $user_name = $c->user()->get_object()->get_username();
532 my $error;
534 my $design = _parse_design_from_json($c->req->param('design_json'));
535 #print STDERR "\nDesign: " . Dumper $design;
537 my @locations;
538 my $multi_location;
539 #print STDERR Dumper $c->req->params();
540 my $locations = $c->req->param('trial_location');
541 my $trial_name = $c->req->param('project_name');
542 my $trial_type = $c->req->param('trial_type');
543 my $breeding_program = $c->req->param('breeding_program_name');
544 my $trial_stock_type = $c->req->param('trial_stock_type');
545 my $field_size = $c->req->param('field_size');
546 my $plot_width = $c->req->param('plot_width');
547 my $plot_length = $c->req->param('plot_length');
548 my $field_trial_is_planned_to_be_genotyped = $c->req->param('field_trial_is_planned_to_be_genotyped') || 'No';
549 my $field_trial_is_planned_to_cross = $c->req->param('field_trial_is_planned_to_cross') || 'No';
550 my @add_project_trial_source = $c->req->param('add_project_trial_source[]');
551 my $add_project_trial_genotype_trial;
552 my $add_project_trial_crossing_trial;
553 my $add_project_trial_genotype_trial_select = [$add_project_trial_genotype_trial];
554 my $add_project_trial_crossing_trial_select = [$add_project_trial_crossing_trial];
556 my $schema = $c->dbic_schema("Bio::Chado::Schema");
557 my $breeding_program_id = $schema->resultset("Project::Project")->find({name=>$breeding_program})->project_id();
558 my $folder;
559 my $new_trial_id;
561 my $json = JSON::XS->new();
562 try {
563 $multi_location = $json->decode($locations);
564 foreach my $loc (@$multi_location) {
565 push @locations, $loc;
568 catch {
569 push @locations, $locations;
571 my $folder_id;
572 my $parent_folder_id = 0;
573 if (scalar(@locations) > 1) {
575 my $existing = $schema->resultset("Project::Project")->find( { name => $trial_name });
576 if ($existing) {
577 $c->stash->{rest} = { error => "A folder or trial with that name already exists in the database. Please select another name." };
578 return;
581 $folder = CXGN::Trial::Folder->create({
582 bcs_schema => $schema,
583 parent_folder_id => $parent_folder_id,
584 name => $trial_name,
585 breeding_program_id => $breeding_program_id,
586 folder_for_trials => 1
588 $folder_id = $folder->folder_id();
591 my $design_index = 0;
593 foreach my $trial_location (@locations) {
594 my $trial_name = $c->req->param('project_name');
596 if (scalar(@locations) > 1) {
597 my $geolocation_lookup = CXGN::Location::LocationLookup->new(schema => $schema);
599 $geolocation_lookup->set_location_name($trial_location);
600 my $location_id = $geolocation_lookup->get_geolocation()->nd_geolocation_id();
601 my $location_object = CXGN::Location->new( {
602 bcs_schema => $schema,
603 nd_geolocation_id => $location_id,
605 my $abbreviation = $location_object->abbreviation();
607 if ($abbreviation) {
608 $trial_name = $trial_name.$abbreviation;
609 } else {
610 $trial_name = $trial_name.$trial_location;
614 #strip name of any invalid filename characters
615 $trial_name =~ s/[\\\/\s:,"*?<>|]+//;
617 my $trial_location_design = $json->decode($design->[$design_index]);
619 my %trial_info_hash = (
620 chado_schema => $chado_schema,
621 dbh => $dbh,
622 design => $trial_location_design,
623 program => $breeding_program,
624 trial_year => $c->req->param('year'),
625 planting_date => $c->req->param('planting_date'),
626 trial_description => $c->req->param('project_description'),
627 trial_location => $trial_location,
628 trial_name => $trial_name,
629 design_type => $c->req->param('design_type'),
630 trial_type => $trial_type,
631 trial_has_plant_entries => $c->req->param('has_plant_entries'),
632 trial_has_subplot_entries => $c->req->param('has_subplot_entries'),
633 operator => $user_name,
634 owner_id => $user_id,
635 field_trial_is_planned_to_cross => $field_trial_is_planned_to_cross,
636 field_trial_is_planned_to_be_genotyped => $field_trial_is_planned_to_be_genotyped,
637 field_trial_from_field_trial => \@add_project_trial_source,
638 genotyping_trial_from_field_trial => $add_project_trial_genotype_trial_select,
639 crossing_trial_from_field_trial => $add_project_trial_crossing_trial_select,
640 trial_stock_type => $trial_stock_type,
643 if ($field_size){
644 $trial_info_hash{field_size} = $field_size;
646 if ($plot_width){
647 $trial_info_hash{plot_width} = $plot_width;
649 if ($plot_length){
650 $trial_info_hash{plot_length} = $plot_length;
652 my $trial_create = CXGN::Trial::TrialCreate->new(\%trial_info_hash);
654 if ($trial_create->trial_name_already_exists()) {
655 $c->stash->{rest} = {error => "Trial name \"".$trial_create->get_trial_name()."\" already exists" };
656 return;
659 try {
660 $save = $trial_create->save_trial();
661 } catch {
662 $save->{'error'} = $_;
665 if ($save->{'error'}) {
666 if (scalar(@locations) > 1){
667 my $folder = CXGN::Trial::Folder->new({
668 bcs_schema => $chado_schema,
669 folder_id => $folder_id,
671 my $delete_folder = $folder->delete_folder();
673 print STDERR "Error saving trial: ".$save->{'error'};
674 $c->stash->{rest} = {error => $save->{'error'}};
675 return;
676 } elsif ($save->{'trial_id'}) {
678 $design_index++;
680 if ($folder_id) {
681 my $folder1 = CXGN::Trial::Folder->new({
682 bcs_schema => $chado_schema,
683 folder_id => $save->{'trial_id'},
685 $folder1->associate_parent($folder_id);
690 if ($save->{'trial_id'}) {
691 my $trial_id = $save->{'trial_id'};
692 my $time = DateTime->now();
693 my $timestamp = $time->ymd();
694 my $calendar_funcs = CXGN::Calendar->new({});
695 my $formatted_date = $calendar_funcs->check_value_format($timestamp);
696 my $create_date = $calendar_funcs->display_start_date($formatted_date);
698 my %trial_activity;
699 $trial_activity{'Trial Created'}{'user_id'} = $user_id;
700 $trial_activity{'Trial Created'}{'activity_date'} = $create_date;
702 my $trial_activity_obj = CXGN::TrialStatus->new({ bcs_schema => $schema });
703 $trial_activity_obj->trial_activities(\%trial_activity);
704 $trial_activity_obj->parent_id($trial_id);
705 my $activity_prop_id = $trial_activity_obj->store();
706 if (!$activity_prop_id) {
707 $c->stash->{rest} = {error => "Error saving trial activity info" };
708 return;
712 my $bs = CXGN::BreederSearch->new( { dbh=>$dbh, dbname=>$c->config->{dbname}, } );
713 my $refresh = $bs->refresh_matviews($c->config->{dbhost}, $c->config->{dbname}, $c->config->{dbuser}, $c->config->{dbpass}, 'all_but_genoview', 'concurrent', $c->config->{basepath});
715 $c->stash->{rest} = {success => "1", trial_id => $save->{'trial_id'}};
716 return;
720 sub verify_trial_name : Path('/ajax/trial/verify_trial_name') : ActionClass('REST') { }
722 sub verify_trial_name_GET : Args(0) {
723 my ($self, $c) = @_;
724 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
725 my $trial_name = $c->req->param('trial_name');
726 my $error;
727 my %errors;
729 if (!$trial_name) {
730 $c->stash->{rest} = {error => "No trial name supplied"};
731 $c->detach;
734 my $project_rs = $schema->resultset('Project::Project')->find({name=>$trial_name});
736 if ($project_rs){
737 my $error = 'The following trial name has aready been used. Please use a unique name';
738 $c->stash->{rest} = {error => $error};
739 } else {
740 $c->stash->{rest} = {
741 success => "1",
746 sub verify_stock_list : Path('/ajax/trial/verify_stock_list') : ActionClass('REST') { }
748 sub verify_stock_list_POST : Args(0) {
749 my ($self, $c) = @_;
750 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
751 my @stock_names;
752 my $error;
753 my %errors;
754 if ($c->req->param('stock_list')) {
755 @stock_names = @{_parse_list_from_json($c->req->param('stock_list'))};
758 if (!@stock_names) {
759 $c->stash->{rest} = {error => "No stock names supplied"};
760 $c->detach;
763 my $lv = CXGN::List::Validate->new();
764 my @accessions_missing = @{$lv->validate($schema,'accessions',\@stock_names)->{'missing'}};
766 if (scalar(@accessions_missing) > 0){
767 my $error = 'The following accessions are not valid in the database, so you must add them first: '.join ',', @accessions_missing;
768 $c->stash->{rest} = {error => $error};
769 } else {
770 $c->stash->{rest} = {
771 success => "1",
776 sub verify_cross_list : Path('/ajax/trial/verify_cross_list') : ActionClass('REST') { }
778 sub verify_cross_list_POST : Args(0) {
779 my ($self, $c) = @_;
780 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
781 my @stock_names;
782 my $error;
783 my %errors;
784 if ($c->req->param('cross_list')) {
785 @stock_names = @{_parse_list_from_json($c->req->param('cross_list'))};
788 if (!@stock_names) {
789 $c->stash->{rest} = {error => "No stock names supplied"};
790 $c->detach;
793 my $lv = CXGN::List::Validate->new();
794 my @crosses_missing = @{$lv->validate($schema,'crosses',\@stock_names)->{'missing'}};
795 if (scalar(@crosses_missing) > 0){
796 my $error = 'The following crosses are not valid in the database, so you must add them first: '.join ',', @crosses_missing;
797 $c->stash->{rest} = {error => $error};
798 } else {
799 $c->stash->{rest} = {
800 success => "1",
805 sub verify_family_name_list : Path('/ajax/trial/verify_family_name_list') : ActionClass('REST') { }
807 sub verify_family_name_list_POST : Args(0) {
808 my ($self, $c) = @_;
809 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
810 my @stock_names;
811 my $error;
812 my %errors;
813 if ($c->req->param('family_name_list')) {
814 @stock_names = @{_parse_list_from_json($c->req->param('family_name_list'))};
817 if (!@stock_names) {
818 $c->stash->{rest} = {error => "No stock names supplied"};
819 $c->detach;
822 my $lv = CXGN::List::Validate->new();
823 my @family_names_missing = @{$lv->validate($schema,'family_names',\@stock_names)->{'missing'}};
824 if (scalar(@family_names_missing) > 0){
825 my $error = 'The following family names are not valid in the database, so you must add them first: '.join ',', @family_names_missing;
826 $c->stash->{rest} = {error => $error};
827 } else {
828 $c->stash->{rest} = {
829 success => "1",
834 sub verify_seedlot_list : Path('/ajax/trial/verify_seedlot_list') : ActionClass('REST') { }
836 sub verify_seedlot_list_POST : Args(0) {
837 my ($self, $c) = @_;
838 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
839 my $people_schema = $c->dbic_schema('CXGN::People::Schema');
840 my $phenome_schema = $c->dbic_schema('CXGN::Phenome::Schema');
841 my @stock_names;
842 my @seedlot_names;
843 if ($c->req->param('stock_list')) {
844 @stock_names = @{_parse_list_from_json($c->req->param('stock_list'))};
846 if ($c->req->param('seedlot_list')) {
847 @seedlot_names = @{_parse_list_from_json($c->req->param('seedlot_list'))};
849 my $return = CXGN::Stock::Seedlot->verify_seedlot_stock_lists($schema, $people_schema, $phenome_schema, \@stock_names, \@seedlot_names);
851 if (exists($return->{error})){
852 $c->stash->{rest} = { error => $return->{error} };
853 $c->detach();
855 if (exists($return->{success})){
856 $c->stash->{rest} = {
857 success => "1",
858 seedlot_hash => $return->{seedlot_hash}
863 sub _parse_list_from_json {
864 my $list_json = shift;
865 my $json = JSON::XS->new();
866 if ($list_json) {
867 #my $decoded_list = $json->allow_nonref->relaxed->escape_slash->loose->allow_singlequote->allow_barekey->decode($list_json);
868 my $decoded_list = $json->decode($list_json);
869 my @array_of_list_items = @{$decoded_list};
870 return \@array_of_list_items;
872 else {
873 return;
877 sub _parse_design_from_json {
878 my $design_json = shift;
879 my $json = JSON::XS->new();
880 if ($design_json) {
881 #my $decoded_json = $json->allow_nonref->utf8->relaxed->escape_slash->loose->allow_singlequote->allow_barekey->decode($design_json);
882 my $decoded_json = $json->decode($design_json);
883 #my %design = %{$decoded_json};
884 return $decoded_json;
886 else {
887 return;
891 ###################################################################################
893 sub upload_trial_file : Path('/ajax/trial/upload_trial_file') : ActionClass('REST') { }
895 sub upload_trial_file_POST : Args(0) {
896 my ($self, $c) = @_;
898 select(STDERR);
899 $| = 1;
901 print STDERR "Check 1: ".localtime()."\n";
904 #print STDERR Dumper $c->req->params();
905 my $chado_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
906 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema");
907 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema");
908 my $dbh = $c->dbc->dbh;
909 my $program = $c->req->param('trial_upload_breeding_program');
910 my $trial_location = $c->req->param('trial_upload_location');
911 my $trial_name = $c->req->param('trial_upload_name');
912 my $trial_year = $c->req->param('trial_upload_year');
913 my $trial_type = $c->req->param('trial_upload_trial_type');
914 my $trial_description = $c->req->param('trial_upload_description');
915 my $trial_design_method = $c->req->param('trial_upload_design_method');
916 my $field_size = $c->req->param('trial_upload_field_size');
917 my $plot_width = $c->req->param('trial_upload_plot_width');
918 my $plot_length = $c->req->param('trial_upload_plot_length');
919 my $field_trial_is_planned_to_be_genotyped = $c->req->param('upload_trial_trial_will_be_genotyped');
920 my $field_trial_is_planned_to_cross = $c->req->param('upload_trial_trial_will_be_crossed');
921 my @add_project_trial_source = $c->req->param('upload_trial_trial_source_select');
922 my $add_project_trial_genotype_trial;
923 my $add_project_trial_crossing_trial;
924 my $add_project_trial_genotype_trial_select = [$add_project_trial_genotype_trial];
925 my $add_project_trial_crossing_trial_select = [$add_project_trial_crossing_trial];
926 my $trial_stock_type = $c->req->param('trial_upload_trial_stock_type');
927 my $ignore_warnings = $c->req->param('upload_trial_ignore_warnings');
929 my $upload = $c->req->upload('trial_uploaded_file');
930 my $parser;
931 my $parsed_data;
932 my $upload_original_name = $upload->filename();
933 my $upload_tempfile = $upload->tempname;
934 my $subdirectory = "trial_upload";
935 my $archived_filename_with_path;
936 my $md5;
937 my $validate_file;
938 my $parsed_file;
939 my $parse_errors;
940 my %parsed_data;
941 my %upload_metadata;
942 my $time = DateTime->now();
943 my $timestamp = $time->ymd()."_".$time->hms();
944 my $user_id;
945 my $user_name;
946 my $error;
947 my $save;
949 print STDERR "Check 2: ".localtime()."\n";
951 if ($upload_original_name =~ /\s/ || $upload_original_name =~ /\// || $upload_original_name =~ /\\/ ) {
952 print STDERR "File name must not have spaces or slashes.\n";
953 $c->stash->{rest} = {error => "Uploaded file name must not contain spaces or slashes." };
954 return;
957 if (!$c->user()) {
958 print STDERR "User not logged in... not uploading a trial.\n";
959 $c->stash->{rest} = {error => "You need to be logged in to upload a trial." };
960 return;
962 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) {
963 $c->stash->{rest} = {error => "You have insufficient privileges to upload a trial." };
964 return;
967 $user_id = $c->user()->get_object()->get_sp_person_id();
968 $user_name = $c->user()->get_object()->get_username();
970 ## Store uploaded temporary file in archive
971 my $uploader = CXGN::UploadFile->new({
972 tempfile => $upload_tempfile,
973 subdirectory => $subdirectory,
974 archive_path => $c->config->{archive_path},
975 archive_filename => $upload_original_name,
976 timestamp => $timestamp,
977 user_id => $user_id,
978 user_role => $c->user->get_object->get_user_type()
980 $archived_filename_with_path = $uploader->archive();
981 $md5 = $uploader->get_md5($archived_filename_with_path);
982 if (!$archived_filename_with_path) {
983 $c->stash->{rest} = {error => "Could not save file $upload_original_name in archive",};
984 return;
986 unlink $upload_tempfile;
988 print STDERR "Check 3: ".localtime()."\n";
990 $upload_metadata{'archived_file'} = $archived_filename_with_path;
991 $upload_metadata{'archived_file_type'}="trial upload file";
992 $upload_metadata{'user_id'}=$user_id;
993 $upload_metadata{'date'}="$timestamp";
995 #parse uploaded file with appropriate plugin
996 $parser = CXGN::Trial::ParseUpload->new(chado_schema => $chado_schema, filename => $archived_filename_with_path, trial_stock_type => $trial_stock_type, trial_name => $trial_name);
997 $parser->load_plugin('TrialExcelFormat');
998 $parsed_data = $parser->parse();
1000 if (!$parsed_data) {
1001 my $return_error = '';
1003 if (! $parser->has_parse_errors() ){
1004 $return_error = "Could not get parsing errors";
1005 $c->stash->{rest} = {error_string => $return_error,};
1007 else {
1008 $parse_errors = $parser->get_parse_errors();
1009 #print STDERR Dumper $parse_errors;
1011 foreach my $error_string (@{$parse_errors->{'error_messages'}}){
1012 $return_error=$return_error.$error_string."<br>";
1016 $c->stash->{rest} = {error_string => $return_error, missing_accessions => $parse_errors->{'missing_stocks'}, missing_seedlots => $parse_errors->{'missing_seedlots'}};
1017 return;
1020 if ($parser->has_parse_warnings()) {
1021 unless ($ignore_warnings) {
1022 my $warnings = $parser->get_parse_warnings();
1023 $c->stash->{rest} = {warnings => $warnings->{'warning_messages'}};
1024 return;
1028 print STDERR "Check 4: ".localtime()."\n";
1030 #print STDERR Dumper $parsed_data;
1032 my $coderef = sub {
1034 my %trial_info_hash = (
1035 chado_schema => $chado_schema,
1036 dbh => $dbh,
1037 owner_id => $user_id,
1038 trial_year => $trial_year,
1039 trial_description => $trial_description,
1040 trial_location => $trial_location,
1041 trial_type => $trial_type,
1042 trial_name => $trial_name,
1043 design_type => $trial_design_method,
1044 design => $parsed_data->{'design'},
1045 program => $program,
1046 upload_trial_file => $upload,
1047 operator => $user_name,
1048 owner_id => $user_id,
1049 field_trial_is_planned_to_cross => $field_trial_is_planned_to_cross,
1050 field_trial_is_planned_to_be_genotyped => $field_trial_is_planned_to_be_genotyped,
1051 field_trial_from_field_trial => \@add_project_trial_source,
1052 genotyping_trial_from_field_trial => $add_project_trial_genotype_trial_select,
1053 crossing_trial_from_field_trial => $add_project_trial_crossing_trial_select,
1054 trial_stock_type => $trial_stock_type
1056 my $entry_numbers = $parsed_data->{'entry_numbers'};
1058 print STDERR "Trial type is ".$trial_info_hash{'trial_type'}."\n";
1060 if ($field_size){
1061 $trial_info_hash{field_size} = $field_size;
1063 if ($plot_width){
1064 $trial_info_hash{plot_width} = $plot_width;
1066 if ($plot_length){
1067 $trial_info_hash{plot_length} = $plot_length;
1069 my $trial_create = CXGN::Trial::TrialCreate->new(\%trial_info_hash);
1070 $save = $trial_create->save_trial();
1072 if ($save->{error}){
1073 $chado_schema->txn_rollback();
1076 # save entry numbers, if provided
1077 if ( $entry_numbers && scalar(keys %$entry_numbers) > 0 && $save->{'trial_id'} ) {
1078 my %entry_numbers_prop;
1079 my @stock_names = keys %$entry_numbers;
1081 # Convert stock names from parsed trial template to stock ids for data storage
1082 my $stocks = $chado_schema->resultset('Stock::Stock')->search({ uniquename=>{-in=>\@stock_names} });
1083 while (my $s = $stocks->next()) {
1084 $entry_numbers_prop{$s->stock_id} = $entry_numbers->{$s->uniquename};
1087 # Lookup synonyms of accession names
1088 my $synonym_cvterm_id = SGN::Model::Cvterm->get_cvterm_row($chado_schema, 'stock_synonym', 'stock_property')->cvterm_id();
1089 my $acc_synonym_rs = $chado_schema->resultset("Stock::Stock")->search({
1090 'me.is_obsolete' => { '!=' => 't' },
1091 'stockprops.value' => { -in => \@stock_names},
1092 'stockprops.type_id' => $synonym_cvterm_id
1093 },{join => 'stockprops', '+select'=>['stockprops.value'], '+as'=>['synonym']});
1094 while (my $r=$acc_synonym_rs->next) {
1095 if ( exists($entry_numbers->{$r->get_column('synonym')}) ) {
1096 $entry_numbers_prop{$r->stock_id} = $entry_numbers->{$r->get_column('synonym')};
1100 # store entry numbers
1101 my $trial = CXGN::Trial->new({ bcs_schema => $chado_schema, trial_id => $save->{'trial_id'} });
1102 $trial->set_entry_numbers(\%entry_numbers_prop);
1106 try {
1107 $chado_schema->txn_do($coderef);
1108 } catch {
1109 print STDERR "Transaction Error: $_\n";
1110 $save->{'error'} = $_;
1113 if ($save->{'trial_id'}) {
1114 my $trial_id = $save->{'trial_id'};
1115 my $timestamp = $time->ymd();
1116 my $calendar_funcs = CXGN::Calendar->new({});
1117 my $formatted_date = $calendar_funcs->check_value_format($timestamp);
1118 my $upload_date = $calendar_funcs->display_start_date($formatted_date);
1120 my %trial_activity;
1121 $trial_activity{'Trial Uploaded'}{'user_id'} = $user_id;
1122 $trial_activity{'Trial Uploaded'}{'activity_date'} = $upload_date;
1124 my $trial_activity_obj = CXGN::TrialStatus->new({ bcs_schema => $chado_schema });
1125 $trial_activity_obj->trial_activities(\%trial_activity);
1126 $trial_activity_obj->parent_id($trial_id);
1127 my $activity_prop_id = $trial_activity_obj->store();
1130 #print STDERR "Check 5: ".localtime()."\n";
1131 if ($save->{'error'}) {
1132 print STDERR "Error saving trial: ".$save->{'error'};
1133 $c->stash->{rest} = {error => $save->{'error'}};
1134 return;
1135 } elsif ($save->{'trial_id'}) {
1137 my $dbh = $c->dbc->dbh();
1138 my $bs = CXGN::BreederSearch->new( { dbh=>$dbh, dbname=>$c->config->{dbname}, } );
1139 my $refresh = $bs->refresh_matviews($c->config->{dbhost}, $c->config->{dbname}, $c->config->{dbuser}, $c->config->{dbpass}, 'all_but_genoview', 'concurrent', $c->config->{basepath});
1141 $c->stash->{rest} = {success => "1", trial_id => $save->{'trial_id'}};
1142 return;
1147 sub upload_multiple_trial_designs_file : Path('/ajax/trial/upload_multiple_trial_designs_file') : ActionClass('REST') { }
1149 sub upload_multiple_trial_designs_file_POST : Args(0) {
1150 my ($self, $c) = @_;
1152 # print STDERR "Check 1: ".localtime()."\n";
1154 # print STDERR Dumper $c->req->params();
1155 my $chado_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
1156 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema");
1157 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema");
1158 my $dbh = $c->dbc->dbh;
1159 my $upload = $c->req->upload('multiple_trial_designs_upload_file');
1160 my $ignore_warnings = $c->req->param('upload_multiple_trials_ignore_warnings');
1161 my $dir = $c->tempfiles_subdir('/delete_nd_experiment_ids');
1162 my $dbhost = $c->config->{dbhost};
1163 my $dbname = $c->config->{dbname};
1164 my $dbpass = $c->config->{dbpass};
1165 my $basepath = $c->config->{basepath};
1166 my $dbuser = $c->config->{dbuser};
1167 my $temp_file_nd_experiment_id = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'delete_nd_experiment_ids/fileXXXX');
1168 my $time = DateTime->now();
1169 my $timestamp = $time->ymd()."_".$time->hms();
1170 my $upload_original_name = $upload->filename();
1171 my $upload_tempfile = $upload->tempname;
1172 my $subdirectory = "trial_upload";
1173 my $archive_filename = $timestamp . "_" . $upload_original_name;
1174 my $archived_filename_with_path;
1175 my $parser;
1176 my $parsed_data;
1177 my $md5;
1178 my $validate_file;
1179 my $parsed_file;
1180 my $parse_errors;
1181 my %parsed_data;
1182 my %upload_metadata;
1183 my $user_id;
1184 my $username;
1185 my $error;
1186 my $email_address ;
1187 my $email_option_enabled;
1188 my $breeding_program_name;
1191 # print STDERR "Check 2: ".localtime()."\n";
1192 print STDERR "Ignore warnings is $ignore_warnings\n";
1193 if ($upload_original_name =~ /\s/ || $upload_original_name =~ /\// || $upload_original_name =~ /\\/ ) {
1194 print STDERR "File name must not have spaces or slashes.\n";
1195 $c->stash->{rest} = {errors => "Uploaded file name must not contain spaces or slashes." };
1196 return;
1199 if (!$c->user()) {
1200 print STDERR "User not logged in... not uploading a trial.\n";
1201 $c->stash->{rest} = {errors => "You need to be logged in to upload a trial." };
1202 return;
1204 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) {
1205 $c->stash->{rest} = {errors => "You have insufficient privileges to upload a trial." };
1206 return;
1209 $user_id = $c->user()->get_object()->get_sp_person_id();
1210 $username = $c->user()->get_object()->get_username();
1211 $email_address = $c->req->param('trial_email_address_upload');
1212 $email_option_enabled = $c->req->param('email_option_to_recieve_trial_upload_status') eq 'on';
1214 print STDERR "email option enabled : $email_option_enabled\n";
1215 print STDERR "recieved address: $email_address\n";
1217 ## Store uploaded temporary file in archive
1218 my $uploader = CXGN::UploadFile->new({
1219 tempfile => $upload_tempfile,
1220 subdirectory => $subdirectory,
1221 archive_path => $c->config->{archive_path},
1222 archive_filename => $upload_original_name,
1223 timestamp => $timestamp,
1224 user_id => $user_id,
1225 user_role => $c->user->get_object->get_user_type()
1227 $archived_filename_with_path = $uploader->archive();
1228 $md5 = $uploader->get_md5($archived_filename_with_path);
1229 if (!$archived_filename_with_path) {
1230 $c->stash->{rest} = {errors => "Could not save file $archive_filename in archive",};
1231 return;
1233 unlink $upload_tempfile;
1235 my $infile = $archived_filename_with_path;
1236 # print STDERR "Check 3: ".localtime()."\n";
1237 $upload_metadata{'archived_file'} = $archived_filename_with_path;
1238 $upload_metadata{'archived_file_type'}="trial upload file";
1239 $upload_metadata{'user_id'}=$user_id;
1240 $upload_metadata{'date'}="$timestamp";
1242 #parse uploaded file with appropriate plugin
1243 $parser = CXGN::Trial::ParseUpload->new(chado_schema => $chado_schema, filename => $archived_filename_with_path);
1244 $parser->load_plugin('MultipleTrialDesignExcelFormat');
1245 $parsed_data = $parser->parse();
1246 print STDERR "the parsed data : " . Dumper($parsed_data) . "\n";
1248 # print STDERR "check the parsed data : \n" . Dumper($parsed_data);
1249 if (!$parsed_data) {
1250 my $return_error = '';
1251 my $email_subject = "Errors in multiple trial upload";
1252 my $email_body = "Dear $username, \n\nErrors found. Please fix the following errors and try re-uploading again: $upload_original_name\n\n";
1254 if (! $parser->has_parse_errors() ){
1255 # $c->stash->{rest} = {errors => "Could not get parsing errors"};
1256 # return;
1257 $return_error = "Could not get parsing errors";
1259 else {
1260 # print STDERR "Parse errors are:\n";
1261 # print STDERR Dumper $parse_errors;
1262 $parse_errors = $parser->get_parse_errors();
1263 if (ref($parse_errors) eq 'HASH' && exists $parse_errors->{'error_messages'}) {
1264 $return_error = join("\n", @{$parse_errors->{'error_messages'}});
1266 # $c->stash->{rest} = {errors => $parse_errors->{'error_messages'}};
1267 # return;
1270 #to remove HTML tags in the email message content
1271 $return_error =~ s/<[^>]*>//g;
1273 $email_body .= $return_error;
1274 $email_body .= "\n\nThank you\nHave a nice day\n";
1276 if ($email_option_enabled == 1 && $email_address) {
1277 CXGN::Contact::send_email($email_subject, $email_body, $email_address);
1280 $c->stash->{rest} = {errors => $return_error};
1281 return;
1284 if ($parser->has_parse_warnings()) {
1285 unless ($ignore_warnings) {
1286 my $warnings = $parser->get_parse_warnings();
1287 $c->stash->{rest} = {warnings => $warnings->{'warning_messages'}};
1288 return;
1292 print STDERR "Check 4: ".localtime()."\n";
1293 # extract the breeding_program_name from the trial
1295 for my $trial (values%$parsed_data) {
1296 if (exists $trial->{'breeding_program'}) {
1297 $breeding_program_name = $trial->{'breeding_program'};
1300 unless ($breeding_program_name) {
1301 $c->stash->{rest} = {errors => "Breeding program not found in the uploaded file."};
1302 return;
1304 print STDERR "Breeding program name: $breeding_program_name\n";
1306 # my $projects = CXGN::BreedersToolbox::Projects->new({ schema => $chado_schema });
1307 # my $breeding_program = $projects->get_breeding_program_by_name($breeding_program_name);
1309 my %all_designs = %{$parsed_data};
1310 my %save;
1311 $save{'errors'} = [];
1313 # print STDERR "breeding_program_name: $breeding_program_name \n";
1314 # print STDERR "infile: $infile \n";
1316 my $async_upload = CXGN::Tools::Run->new();
1317 $async_upload->run_async("perl $basepath/bin/upload_multiple_trial_design.pl -H $dbhost -D $dbname -P \"$dbpass\" -w \"$basepath\" -U \"$dbuser\" -b \"$breeding_program_name\" -i \"$infile\" -un \"$username\" -e \"$email_address\" -eo $email_option_enabled -r $temp_file_nd_experiment_id");
1318 #print STDERR "Check 5: ".localtime()."\n";
1319 if (scalar @{$save{'errors'}} > 0) {
1320 print STDERR "Errors saving trials: ".@{$save{'errors'}};
1321 $c->stash->{rest} = {errors => $save{'errors'}};
1322 return;
1323 # } elsif ($save->{'trial_id'}) {
1324 } else {
1325 my $dbh = $c->dbc->dbh();
1326 my $bs = CXGN::BreederSearch->new( { dbh=>$dbh, dbname=>$c->config->{dbname}, } );
1327 my $refresh = $bs->refresh_matviews($c->config->{dbhost}, $c->config->{dbname}, $c->config->{dbuser}, $c->config->{dbpass}, 'all_but_genoview', 'concurrent', $c->config->{basepath});
1329 $c->stash->{rest} = {success => "1",};
1330 return;
1336 sub upload_soil_data : Path('/ajax/trial/upload_soil_data') : ActionClass('REST') { }
1338 sub upload_soil_data_POST : Args(0) {
1339 my ($self, $c) = @_;
1340 my $chado_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
1341 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema");
1342 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema");
1343 my $dbh = $c->dbc->dbh;
1344 my $trial_id = $c->req->param('soil_data_trial_id');
1345 my $description = $c->req->param('soil_data_description');
1346 my $soil_data_date = $c->req->param('changed');
1347 my $soil_data_gps = $c->req->param('soil_data_gps');
1348 my $type_of_sampling = $c->req->param('type_of_sampling');
1350 my $upload = $c->req->upload('soil_data_upload_file');
1351 my $parser;
1352 my $parsed_data;
1353 my $upload_original_name = $upload->filename();
1354 my $upload_tempfile = $upload->tempname;
1355 my $subdirectory = "soil_data_upload";
1356 my $archived_filename_with_path;
1357 my $md5;
1358 my $validate_file;
1359 my $parsed_file;
1360 my $parse_errors;
1361 my %parsed_data;
1362 my %upload_metadata;
1363 my $time = DateTime->now();
1364 my $timestamp = $time->ymd()."_".$time->hms();
1365 my $user_id;
1366 my $user_name;
1367 my $error;
1368 my $user_role;
1369 my $session_id = $c->req->param("sgn_session_id");
1371 if ($upload_original_name =~ /\s/ || $upload_original_name =~ /\// || $upload_original_name =~ /\\/ ) {
1372 print STDERR "File name must not have spaces or slashes.\n";
1373 $c->stash->{rest} = {errors => "Uploaded file name must not contain spaces or slashes." };
1374 return;
1377 if ($session_id){
1378 my $dbh = $c->dbc->dbh;
1379 my @user_info = CXGN::Login->new($dbh)->query_from_cookie($session_id);
1380 if (!$user_info[0]){
1381 $c->stash->{rest} = {error=>'You must be logged in to upload soil data!'};
1382 $c->detach();
1384 $user_id = $user_info[0];
1385 $user_role = $user_info[1];
1386 my $p = CXGN::People::Person->new($dbh, $user_id);
1387 $user_name = $p->get_username;
1388 } else{
1389 if (!$c->user){
1390 $c->stash->{rest} = {error=>'You must be logged in to upload soil data!'};
1391 $c->detach();
1393 $user_id = $c->user()->get_object()->get_sp_person_id();
1394 $user_name = $c->user()->get_object()->get_username();
1395 $user_role = $c->user->get_object->get_user_type();
1398 if (($user_role ne 'curator') && ($user_role ne 'submitter')) {
1399 $c->stash->{rest} = {error=>'Only a submitter or a curator can upload soil data'};
1400 $c->detach();
1403 ## Store uploaded temporary file in archive
1404 my $uploader = CXGN::UploadFile->new({
1405 tempfile => $upload_tempfile,
1406 subdirectory => $subdirectory,
1407 archive_path => $c->config->{archive_path},
1408 archive_filename => $upload_original_name,
1409 timestamp => $timestamp,
1410 user_id => $user_id,
1411 user_role => $user_role
1413 $archived_filename_with_path = $uploader->archive();
1414 $md5 = $uploader->get_md5($archived_filename_with_path);
1415 if (!$archived_filename_with_path) {
1416 $c->stash->{rest} = {errors => "Could not save file $upload_original_name in archive",};
1417 return;
1419 unlink $upload_tempfile;
1421 $upload_metadata{'archived_file'} = $archived_filename_with_path;
1422 $upload_metadata{'archived_file_type'}="soil data upload file";
1423 $upload_metadata{'user_id'}=$user_id;
1424 $upload_metadata{'date'}="$timestamp";
1427 #parse uploaded file with appropriate plugin
1428 $parser = CXGN::Trial::ParseUpload->new(chado_schema => $chado_schema, filename => $archived_filename_with_path);
1429 $parser->load_plugin('SoilDataXLS');
1430 $parsed_data = $parser->parse();
1431 print STDERR "PARSED DATA =".Dumper($parsed_data)."\n";
1433 if (!$parsed_data){
1434 my $return_error = '';
1435 my $parse_errors;
1436 if (!$parser->has_parse_errors() ){
1437 $c->stash->{rest} = {error_string => "Could not get parsing errors"};
1438 } else {
1439 $parse_errors = $parser->get_parse_errors();
1440 #print STDERR Dumper $parse_errors;
1442 foreach my $error_string (@{$parse_errors->{'error_messages'}}){
1443 $return_error .= $error_string."<br>";
1446 $c->stash->{rest} = {error_string => $return_error};
1447 $c->detach();
1448 } else {
1449 my $soil_data_details = $parsed_data->{'soil_data_details'};
1450 my $data_type_order = $parsed_data->{'data_type_order'};
1452 my $soil_data = CXGN::BreedersToolbox::SoilData->new({ bcs_schema => $chado_schema });
1453 $soil_data->parent_id($trial_id);
1454 $soil_data->description($description);
1455 $soil_data->date($soil_data_date);
1456 $soil_data->gps($soil_data_gps);
1457 $soil_data->type_of_sampling($type_of_sampling);
1458 $soil_data->data_type_order($data_type_order);
1459 $soil_data->soil_data_details($soil_data_details);
1461 my $soil_data_prop_id = $soil_data->store();
1462 print STDERR "PROJECTPROP ID =".Dumper($soil_data_prop_id)."\n";
1465 $c->stash->{rest} = {success => "1"};