fix password reset link.
[sgn.git] / lib / SGN / Controller / AJAX / Trial.pm
blob4b94d33a9aaa0e35ff91ecd30f9ae5f4d790a068
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 Try::Tiny;
22 use Scalar::Util qw(looks_like_number);
23 use DateTime;
24 use File::Basename qw | basename dirname|;
25 use File::Copy;
26 use File::Slurp;
27 use File::Spec::Functions;
28 use Digest::MD5;
29 use List::MoreUtils qw /any /;
30 use Data::Dumper;
31 use CXGN::Trial;
32 use CXGN::Trial::TrialDesign;
33 use CXGN::Trial::TrialCreate;
34 use JSON -support_by_pp;
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;
47 use CXGN::BreedersToolbox::Accessions;
48 use CXGN::BreederSearch;
50 BEGIN { extends 'Catalyst::Controller::REST' }
52 __PACKAGE__->config(
53 default => 'application/json',
54 stash_key => 'rest',
55 map => { 'application/json' => 'JSON', 'text/html' => 'JSON' },
58 has 'schema' => (
59 is => 'rw',
60 isa => 'DBIx::Class::Schema',
61 lazy_build => 1,
65 sub generate_experimental_design : Path('/ajax/trial/generate_experimental_design') : ActionClass('REST') { }
67 sub generate_experimental_design_POST : Args(0) {
68 my ($self, $c) = @_;
69 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
70 my $trial_design = CXGN::Trial::TrialDesign->new();
71 my %design;
72 my %design_info;
73 my $error;
74 my $project_name = $c->req->param('project_name');
75 my $project_description = $c->req->param('project_description');
76 my $year = $c->req->param('year');
77 my @stock_names;
78 my $design_layout_view_html;
79 my $design_info_view_html;
80 my $design_map_view;
81 if ($c->req->param('stock_list')) {
82 @stock_names = @{_parse_list_from_json($c->req->param('stock_list'))};
84 my $seedlot_hash_json = $c->req->param('seedlot_hash');
85 my @control_names;
86 if ($c->req->param('control_list')) {
87 @control_names = @{_parse_list_from_json($c->req->param('control_list'))};
90 my @control_names_crbd;
91 if ($c->req->param('control_list_crbd')) {
92 @control_names_crbd = @{_parse_list_from_json($c->req->param('control_list_crbd'))};
95 my $design_type = $c->req->param('design_type');
96 my $rep_count = $c->req->param('rep_count');
97 my $block_number = $c->req->param('block_number');
99 my $row_number = $c->req->param('row_number');
100 my $block_row_number=$c->req->param('row_number_per_block');
101 my $block_col_number=$c->req->param('col_number_per_block');
102 my $col_number =$c->req->param('col_number');
104 my $block_size = $c->req->param('block_size');
105 my $max_block_size = $c->req->param('max_block_size');
106 my $plot_prefix = $c->req->param('plot_prefix');
107 my $start_number = $c->req->param('start_number');
108 my $increment = $c->req->param('increment');
109 my $trial_location = $c->req->param('trial_location');
110 my $fieldmap_col_number = $c->req->param('fieldmap_col_number');
111 my $fieldmap_row_number = $c->req->param('fieldmap_row_number');
112 my $plot_layout_format = $c->req->param('plot_layout_format');
113 my @treatments = $c->req->param('treatments[]');
114 my $num_plants_per_plot = $c->req->param('num_plants_per_plot');
115 my $num_seed_per_plot = $c->req->param('num_seed_per_plot');
116 my $westcott_check_1 = $c->req->param('westcott_check_1');
117 my $westcott_check_2 = $c->req->param('westcott_check_2');
118 my $westcott_col = $c->req->param('westcott_col');
119 my $westcott_col_between_check = $c->req->param('westcott_col_between_check');
121 my $field_size = $c->req->param('field_size');
122 my $plot_width = $c->req->param('plot_width');
123 my $plot_length = $c->req->param('plot_length');
125 if ($design_type eq 'westcott'){
126 if (!$westcott_check_1){
127 $c->stash->{rest} = { error => "You need to provide name of check 1 for westcott design."};
128 return;
130 if (!$westcott_check_2){
131 $c->stash->{rest} = { error => "You need to provide name of check 2 for westcott design."};
132 return;
134 if (!$westcott_col){
135 $c->stash->{rest} = { error => "You need to provide number of columns for westcott design."};
136 return;
138 push @control_names_crbd, $westcott_check_1;
139 push @control_names_crbd, $westcott_check_2;
142 if ($design_type eq 'splitplot'){
143 if (scalar(@treatments)<1){
144 $c->stash->{rest} = { error => "You need to provide at least one treatment for a splitplot design."};
145 return;
147 if (!$num_plants_per_plot){
148 $c->stash->{rest} = { error => "You need to provide number of plants per treatment for a splitplot design."};
149 return;
151 if ($num_plants_per_plot <1){
152 $c->stash->{rest} = { error => "You need to provide number of plants per treatment for a splitplot design."};
153 return;
155 if (($num_plants_per_plot%(scalar(@treatments)))!=0){
156 $c->stash->{rest} = {error => "Number of plants per plot needs to divide evenly by the number of treatments. For example: if you have two treatments and there are 3 plants per treatment, that means you have 6 plants per plot." };
157 return;
161 my $row_in_design_number = $c->req->param('row_in_design_number');
162 my $col_in_design_number = $c->req->param('col_in_design_number');
163 my $no_of_rep_times = $c->req->param('no_of_rep_times');
164 my $no_of_block_sequence = $c->req->param('no_of_block_sequence');
165 my $unreplicated_accession_list = $c->req->param('unreplicated_accession_list');
166 my $replicated_accession_list = $c->req->param('replicated_accession_list');
167 my $no_of_sub_block_sequence = $c->req->param('no_of_sub_block_sequence');
169 my @replicated_accession;
170 if ($c->req->param('replicated_accession_list')) {
171 @replicated_accession = @{_parse_list_from_json($c->req->param('replicated_accession_list'))};
173 my $number_of_replicated_accession = scalar(@replicated_accession);
175 my @unreplicated_accession;
176 if ($c->req->param('unreplicated_accession_list')) {
177 @unreplicated_accession = @{_parse_list_from_json($c->req->param('unreplicated_accession_list'))};
179 my $number_of_unreplicated_accession = scalar(@unreplicated_accession);
182 my $greenhouse_num_plants = $c->req->param('greenhouse_num_plants');
183 my $use_same_layout = $c->req->param('use_same_layout');
184 my $number_of_checks = scalar(@control_names_crbd);
186 if ($design_type eq "RCBD" || $design_type eq "Alpha" || $design_type eq "CRD" || $design_type eq "Lattice") {
187 if (@control_names_crbd) {
188 @stock_names = (@stock_names, @control_names_crbd);
191 if($design_type eq "p-rep"){
192 @stock_names = (@replicated_accession, @unreplicated_accession);
194 #print STDERR Dumper(\@stock_names);
195 my $number_of_prep_accession = scalar(@stock_names);
196 my $p_rep_total_plots = $row_in_design_number * $col_in_design_number;
197 my $replicated_plots = $no_of_rep_times * $number_of_replicated_accession;
198 my $unreplicated_plots = scalar(@unreplicated_accession);
199 my $calculated_total_plot = $replicated_plots + $unreplicated_plots;
201 my @locations;
202 my $trial_locations;
203 my $multi_location;
205 try {
206 $multi_location = decode_json($trial_location);
207 foreach my $loc (@$multi_location) {
208 push @locations, $loc;
211 catch {
212 push @locations, $trial_location;
215 my $location_number = scalar(@locations);
217 #print STDERR Dumper(@locations);
219 if (!$c->user()) {
220 $c->stash->{rest} = {error => "You need to be logged in to add a trial" };
221 return;
224 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) { #user must have privileges to add a trial
225 $c->stash->{rest} = {error => "You have insufficient privileges to add a trial." };
226 return;
228 #print "TOTAL PLOTS $p_rep_total_plots AND CALCULATED PLOTS $calculated_total_plot\n";
229 if($p_rep_total_plots != $calculated_total_plot){
230 $c->stash->{rest} = {error => "Treatment repeats do not equal number of plots in design" };
231 return;
234 my @design_array;
235 my @design_layout_view_html_array;
237 foreach $trial_locations (@locations) {
239 my $trial_name = $c->req->param('project_name');
240 my $geolocation_lookup = CXGN::Location::LocationLookup->new(schema => $schema);
242 $geolocation_lookup->set_location_name($trial_locations);
243 #print STDERR Dumper(\$geolocation_lookup);
244 if (!$geolocation_lookup->get_geolocation()){
245 $c->stash->{rest} = { error => "Trial location not found" };
246 return;
249 if (scalar(@locations) > 1) {
250 $trial_name = $trial_name."_".$trial_locations;
253 $trial_design->set_trial_name($trial_name);
255 my $design_created = 0;
256 if ($use_same_layout) {
257 $design_created = 1;
260 if ($design_created) {
261 $trial_design->set_randomization_seed($design_created);
264 if (@stock_names) {
265 $trial_design->set_stock_list(\@stock_names);
266 $design_info{'number_of_stocks'} = scalar(@stock_names);
267 } else {
268 $c->stash->{rest} = {error => "No list of stocks supplied." };
269 return;
271 if ($seedlot_hash_json){
272 my $json = JSON->new();
273 $trial_design->set_seedlot_hash($json->decode($seedlot_hash_json));
275 if ($num_seed_per_plot){
276 $trial_design->set_num_seed_per_plot($num_seed_per_plot);
278 if (@control_names) {
279 $trial_design->set_control_list(\@control_names);
280 $design_info{'number_of_controls'} = scalar(@control_names);
282 if (@control_names_crbd) {
283 $trial_design->set_control_list_crbd(\@control_names_crbd);
284 $design_info{'number_of_controls_crbd'} = scalar(@control_names_crbd);
286 if ($start_number) {
287 $trial_design->set_plot_start_number($start_number);
288 } else {
289 $trial_design->clear_plot_start_number();
291 if ($increment) {
292 $trial_design->set_plot_number_increment($increment);
293 } else {
294 $trial_design->clear_plot_number_increment();
296 if ($plot_prefix) {
297 $trial_design->set_plot_name_prefix($plot_prefix);
299 if ($rep_count) {
300 $trial_design->set_number_of_reps($rep_count);
302 if ($block_number) {
303 $trial_design->set_number_of_blocks($block_number);
305 if($row_number){
306 $trial_design->set_number_of_rows($row_number);
308 if($block_row_number){
309 $trial_design->set_block_row_numbers($block_row_number);
311 if($block_col_number){
312 $trial_design->set_block_col_numbers($block_col_number);
314 if($col_number){
315 $trial_design->set_number_of_cols($col_number);
317 if ($block_size) {
318 $trial_design->set_block_size($block_size);
320 if ($max_block_size) {
321 $trial_design->set_maximum_block_size($max_block_size);
323 if ($greenhouse_num_plants) {
324 my $json = JSON->new();
325 $trial_design->set_greenhouse_num_plants($json->decode($greenhouse_num_plants));
327 if ($westcott_check_1){
328 $trial_design->set_westcott_check_1($westcott_check_1);
330 if ($westcott_check_2){
331 $trial_design->set_westcott_check_2($westcott_check_2);
333 if ($westcott_col){
334 $trial_design->set_westcott_col($westcott_col);
336 if ($westcott_col_between_check){
337 $trial_design->set_westcott_col_between_check($westcott_col_between_check);
339 if ($location_number) {
340 $design_info{'number_of_locations'} = $location_number;
342 if($number_of_checks){
343 $design_info{'number_of_checks'} = $number_of_checks;
345 if ($design_type) {
346 $trial_design->set_design_type($design_type);
347 $design_info{'design_type'} = $design_type;
348 } else {
349 $c->stash->{rest} = {error => "No design type supplied." };
350 return;
352 if (!$trial_design->has_design_type()) {
353 $c->stash->{rest} = {error => "Design type not supported." };
354 return;
356 if ($fieldmap_col_number) {
357 $trial_design->set_fieldmap_col_number($fieldmap_col_number);
359 if ($fieldmap_row_number) {
360 $trial_design->set_fieldmap_row_number($fieldmap_row_number);
362 if ($plot_layout_format) {
363 $trial_design->set_plot_layout_format($plot_layout_format);
365 if ($number_of_replicated_accession) {
366 $trial_design->set_replicated_accession_no($number_of_replicated_accession);
368 if ($number_of_unreplicated_accession) {
369 $trial_design->set_unreplicated_accession_no($number_of_unreplicated_accession);
371 if ($row_in_design_number) {
372 $trial_design->set_row_in_design_number($row_in_design_number);
374 if ($col_in_design_number) {
375 $trial_design->set_col_in_design_number($col_in_design_number);
377 if ($no_of_rep_times) {
378 $trial_design->set_num_of_replicated_times($no_of_rep_times);
380 if ($no_of_block_sequence) {
381 $trial_design->set_block_sequence($no_of_block_sequence);
383 if ($no_of_sub_block_sequence) {
384 $trial_design->set_sub_block_sequence($no_of_sub_block_sequence);
387 if (scalar(@treatments)>0) {
388 $trial_design->set_treatments(\@treatments);
390 if($num_plants_per_plot){
391 $trial_design->set_num_plants_per_plot($num_plants_per_plot);
394 try {
395 $trial_design->calculate_design();
396 } catch {
397 $c->stash->{rest} = {error => "Could not calculate design: $_"};
398 $error=1;
400 if ($error) {
401 return;
403 if ($trial_design->get_design()) {
404 %design = %{$trial_design->get_design()};
405 #print STDERR "DESIGN: ". Dumper(%design);
406 } else {
407 $c->stash->{rest} = {error => "Could not generate design" };
408 return;
410 my $design_level;
411 if ($design_type eq 'greenhouse'){
412 $design_level = 'plants';
413 } elsif ($design_type eq 'splitplot') {
414 $design_level = 'subplots';
415 } else {
416 $design_level = 'plots';
419 $design_map_view = design_layout_map_view(\%design, $design_type);
420 $design_layout_view_html = design_layout_view(\%design, \%design_info, $design_level);
421 $design_info_view_html = design_info_view(\%design, \%design_info);
422 my $design_json = encode_json(\%design);
423 push @design_array, $design_json;
424 push @design_layout_view_html_array, $design_layout_view_html;
427 my $warning_message;
428 #check if field size can fit the design_json
429 if ($field_size && $plot_width && $plot_length){
430 my $num_plots = scalar( keys %{decode_json $design_array[0]} );
431 my $total_area = $plot_width * $plot_length * $num_plots; #sq meters. 1 ha = 10000m2
432 my $field_size_m = $field_size * 10000;
433 if ($field_size_m < $total_area){
434 $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.";
435 } else {
436 $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).";
440 $c->stash->{rest} = {
441 success => "1",
442 design_layout_view_html => encode_json(\@design_layout_view_html_array),
443 design_info_view_html => $design_info_view_html,
444 design_map_view => $design_map_view,
445 design_json => encode_json(\@design_array),
446 warning_message => $warning_message
452 sub save_experimental_design : Path('/ajax/trial/save_experimental_design') : ActionClass('REST') { }
454 sub save_experimental_design_POST : Args(0) {
455 my ($self, $c) = @_;
456 my $chado_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
457 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema");
458 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema");
459 my $dbh = $c->dbc->dbh;
461 print STDERR "Saving trial... :-)\n";
464 if (!$c->user()) {
465 $c->stash->{rest} = {error => "You need to be logged in to add a trial" };
466 return;
468 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) {
469 $c->stash->{rest} = {error => "You have insufficient privileges to add a trial." };
470 return;
472 my $user_id = $c->user()->get_object()->get_sp_person_id();
474 my $user_name = $c->user()->get_object()->get_username();
475 my $error;
477 my $design = _parse_design_from_json($c->req->param('design_json'));
478 #print STDERR "\nDesign: " . Dumper $design;
480 my @locations;
481 my $trial_location;
482 my $multi_location;
483 #print STDERR Dumper $c->req->params();
484 my $trial_locations = $c->req->param('trial_location');
485 my $trial_name = $c->req->param('project_name');
486 my $trial_type = $c->req->param('trial_type');
487 my $breeding_program = $c->req->param('breeding_program_name');
488 my $field_size = $c->req->param('field_size');
489 my $plot_width = $c->req->param('plot_width');
490 my $plot_length = $c->req->param('plot_length');
491 my $field_trial_is_planned_to_be_genotyped = $c->req->param('field_trial_is_planned_to_be_genotyped') || 'No';
492 my $field_trial_is_planned_to_cross = $c->req->param('field_trial_is_planned_to_cross') || 'No';
493 my $add_project_trial_source = $c->req->param('add_project_trial_source[]');
494 my $add_project_trial_genotype_trial;
495 my $add_project_trial_crossing_trial;
496 my $add_project_trial_source_select = ref($add_project_trial_source) eq 'ARRAY' ? $add_project_trial_source : [$add_project_trial_source];
497 my $add_project_trial_genotype_trial_select = [$add_project_trial_genotype_trial];
498 my $add_project_trial_crossing_trial_select = [$add_project_trial_crossing_trial];
500 my $schema = $c->dbic_schema("Bio::Chado::Schema");
501 my $breeding_program_id = $schema->resultset("Project::Project")->find({name=>$breeding_program})->project_id();
502 my $folder;
503 my $new_trial_id;
505 try {
506 $multi_location = decode_json($trial_locations);
507 foreach my $loc (@$multi_location) {
508 push @locations, $loc;
511 catch {
512 push @locations, $trial_locations;
514 my $folder_id;
515 my $parent_folder_id = 0;
516 if (scalar(@locations) > 1) {
518 my $existing = $schema->resultset("Project::Project")->find( { name => $trial_name });
519 if ($existing) {
520 $c->stash->{rest} = { error => "An folder or trial with that name already exists in the database. Please select another name." };
521 return;
524 $folder = CXGN::Trial::Folder->create({
525 bcs_schema => $schema,
526 parent_folder_id => $parent_folder_id,
527 name => $trial_name,
528 breeding_program_id => $breeding_program_id,
529 folder_for_trials => 1
531 $folder_id = $folder->folder_id();
534 my $design_index = 0;
536 foreach $trial_location (@locations) {
537 my $trial_name = $c->req->param('project_name');
538 if (scalar(@locations) > 1) {
539 $trial_name = $trial_name."_".$trial_location;
542 my $trial_location_design = decode_json($design->[$design_index]);
543 #print STDERR Dumper $trial_location_design;
545 my %trial_info_hash = (
546 chado_schema => $chado_schema,
547 dbh => $dbh,
548 user_name => $user_name, #not implemented
549 design => $trial_location_design,
550 program => $breeding_program,
551 trial_year => $c->req->param('year'),
552 trial_description => $c->req->param('project_description'),
553 trial_location => $trial_location,
554 trial_name => $trial_name,
555 design_type => $c->req->param('design_type'),
556 trial_type => $trial_type,
557 trial_has_plant_entries => $c->req->param('has_plant_entries'),
558 trial_has_subplot_entries => $c->req->param('has_subplot_entries'),
559 operator => $user_name,
560 field_trial_is_planned_to_cross => $field_trial_is_planned_to_cross,
561 field_trial_is_planned_to_be_genotyped => $field_trial_is_planned_to_be_genotyped,
562 field_trial_from_field_trial => $add_project_trial_source_select,
563 genotyping_trial_from_field_trial => $add_project_trial_genotype_trial_select,
564 crossing_trial_from_field_trial => $add_project_trial_crossing_trial_select,
567 if ($field_size){
568 $trial_info_hash{field_size} = $field_size;
570 if ($plot_width){
571 $trial_info_hash{plot_width} = $plot_width;
573 if ($plot_length){
574 $trial_info_hash{plot_length} = $plot_length;
577 my $trial_create = CXGN::Trial::TrialCreate->new(\%trial_info_hash);
579 if ($trial_create->trial_name_already_exists()) {
580 $c->stash->{rest} = {error => "Trial name \"".$trial_create->get_trial_name()."\" already exists" };
581 return;
584 my $save;
585 try {
586 $save = $trial_create->save_trial();
587 } catch {
588 $save->{'error'} = $_;
591 if ($save->{'error'}) {
592 if (scalar(@locations) > 1){
593 my $folder = CXGN::Trial::Folder->new({
594 bcs_schema => $chado_schema,
595 folder_id => $folder_id,
597 my $delete_folder = $folder->delete_folder();
599 print STDERR "Error saving trial: ".$save->{'error'};
600 $c->stash->{rest} = {error => $save->{'error'}};
601 return;
602 } elsif ($save->{'trial_id'}) {
604 $design_index++;
606 if ($folder_id) {
607 my $folder1 = CXGN::Trial::Folder->new({
608 bcs_schema => $chado_schema,
609 folder_id => $save->{'trial_id'},
611 $folder1->associate_parent($folder_id);
616 my $bs = CXGN::BreederSearch->new( { dbh=>$dbh, dbname=>$c->config->{dbname}, } );
617 my $refresh = $bs->refresh_matviews($c->config->{dbhost}, $c->config->{dbname}, $c->config->{dbuser}, $c->config->{dbpass}, 'stockprop');
619 $c->stash->{rest} = {success => "1",};
620 return;
624 sub verify_trial_name : Path('/ajax/trial/verify_trial_name') : ActionClass('REST') { }
626 sub verify_trial_name_GET : Args(0) {
627 my ($self, $c) = @_;
628 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
629 my $trial_name = $c->req->param('trial_name');
630 my $error;
631 my %errors;
633 if (!$trial_name) {
634 $c->stash->{rest} = {error => "No trial name supplied"};
635 $c->detach;
638 my $project_rs = $schema->resultset('Project::Project')->find({name=>$trial_name});
640 if ($project_rs){
641 my $error = 'The following trial name has aready been used. Please use a unique name';
642 $c->stash->{rest} = {error => $error};
643 } else {
644 $c->stash->{rest} = {
645 success => "1",
650 sub verify_stock_list : Path('/ajax/trial/verify_stock_list') : ActionClass('REST') { }
652 sub verify_stock_list_POST : Args(0) {
653 my ($self, $c) = @_;
654 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
655 my @stock_names;
656 my $error;
657 my %errors;
658 if ($c->req->param('stock_list')) {
659 @stock_names = @{_parse_list_from_json($c->req->param('stock_list'))};
662 if (!@stock_names) {
663 $c->stash->{rest} = {error => "No stock names supplied"};
664 $c->detach;
667 my $lv = CXGN::List::Validate->new();
668 my @accessions_missing = @{$lv->validate($schema,'accessions',\@stock_names)->{'missing'}};
670 if (scalar(@accessions_missing) > 0){
671 my $error = 'The following accessions are not valid in the database, so you must add them first: '.join ',', @accessions_missing;
672 $c->stash->{rest} = {error => $error};
673 } else {
674 $c->stash->{rest} = {
675 success => "1",
680 sub verify_seedlot_list : Path('/ajax/trial/verify_seedlot_list') : ActionClass('REST') { }
682 sub verify_seedlot_list_POST : Args(0) {
683 my ($self, $c) = @_;
684 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
685 my $people_schema = $c->dbic_schema('CXGN::People::Schema');
686 my $phenome_schema = $c->dbic_schema('CXGN::Phenome::Schema');
687 my @stock_names;
688 my @seedlot_names;
689 if ($c->req->param('stock_list')) {
690 @stock_names = @{_parse_list_from_json($c->req->param('stock_list'))};
692 if ($c->req->param('seedlot_list')) {
693 @seedlot_names = @{_parse_list_from_json($c->req->param('seedlot_list'))};
695 my $return = CXGN::Stock::Seedlot->verify_seedlot_stock_lists($schema, $people_schema, $phenome_schema, \@stock_names, \@seedlot_names);
697 if (exists($return->{error})){
698 $c->stash->{rest} = { error => $return->{error} };
699 $c->detach();
701 if (exists($return->{success})){
702 $c->stash->{rest} = {
703 success => "1",
704 seedlot_hash => $return->{seedlot_hash}
709 sub _parse_list_from_json {
710 my $list_json = shift;
711 my $json = new JSON;
712 if ($list_json) {
713 my $decoded_list = $json->allow_nonref->utf8->relaxed->escape_slash->loose->allow_singlequote->allow_barekey->decode($list_json);
714 #my $decoded_list = decode_json($list_json);
715 my @array_of_list_items = @{$decoded_list};
716 return \@array_of_list_items;
718 else {
719 return;
723 sub _parse_design_from_json {
724 my $design_json = shift;
725 my $json = new JSON;
726 if ($design_json) {
727 my $decoded_json = $json->allow_nonref->utf8->relaxed->escape_slash->loose->allow_singlequote->allow_barekey->decode($design_json);
728 #my $decoded_json = decode_json($design_json);
729 #my %design = %{$decoded_json};
730 return $decoded_json;
732 else {
733 return;
737 ###################################################################################
739 sub upload_trial_file : Path('/ajax/trial/upload_trial_file') : ActionClass('REST') { }
741 sub upload_trial_file_POST : Args(0) {
742 my ($self, $c) = @_;
744 print STDERR "Check 1: ".localtime()."\n";
746 my $chado_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
747 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema");
748 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema");
749 my $dbh = $c->dbc->dbh;
750 my $program = $c->req->param('trial_upload_breeding_program');
751 my $trial_location = $c->req->param('trial_upload_location');
752 my $trial_name = $c->req->param('trial_upload_name');
753 my $trial_year = $c->req->param('trial_upload_year');
754 my $trial_type = $c->req->param('trial_upload_trial_type');
755 my $trial_description = $c->req->param('trial_upload_description');
756 my $trial_design_method = $c->req->param('trial_upload_design_method');
757 my $field_size = $c->req->param('trial_upload_field_size');
758 my $plot_width = $c->req->param('trial_upload_plot_width');
759 my $plot_length = $c->req->param('trial_upload_plot_length');
760 my $field_trial_is_planned_to_be_genotyped = $c->req->param('upload_trial_trial_will_be_genotyped');
761 my $field_trial_is_planned_to_cross = $c->req->param('upload_trial_trial_will_be_crossed');
762 my $add_project_trial_source = $c->req->param('upload_trial_trial_source_select');
763 my $add_project_trial_genotype_trial;
764 my $add_project_trial_crossing_trial;
765 my $add_project_trial_source_select = ref($add_project_trial_source) eq 'ARRAY' ? $add_project_trial_source : [$add_project_trial_source];
766 my $add_project_trial_genotype_trial_select = [$add_project_trial_genotype_trial];
767 my $add_project_trial_crossing_trial_select = [$add_project_trial_crossing_trial];
769 my $upload = $c->req->upload('trial_uploaded_file');
770 my $parser;
771 my $parsed_data;
772 my $upload_original_name = $upload->filename();
773 my $upload_tempfile = $upload->tempname;
774 my $subdirectory = "trial_upload";
775 my $archived_filename_with_path;
776 my $md5;
777 my $validate_file;
778 my $parsed_file;
779 my $parse_errors;
780 my %parsed_data;
781 my %upload_metadata;
782 my $time = DateTime->now();
783 my $timestamp = $time->ymd()."_".$time->hms();
784 my $user_id;
785 my $user_name;
786 my $error;
788 print STDERR "Check 2: ".localtime()."\n";
790 if ($upload_original_name =~ /\s/ || $upload_original_name =~ /\// || $upload_original_name =~ /\\/ ) {
791 print STDERR "File name must not have spaces or slashes.\n";
792 $c->stash->{rest} = {error => "Uploaded file name must not contain spaces or slashes." };
793 return;
796 if (!$c->user()) {
797 print STDERR "User not logged in... not uploading a trial.\n";
798 $c->stash->{rest} = {error => "You need to be logged in to upload a trial." };
799 return;
801 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) {
802 $c->stash->{rest} = {error => "You have insufficient privileges to upload a trial." };
803 return;
806 $user_id = $c->user()->get_object()->get_sp_person_id();
807 $user_name = $c->user()->get_object()->get_username();
809 ## Store uploaded temporary file in archive
810 my $uploader = CXGN::UploadFile->new({
811 tempfile => $upload_tempfile,
812 subdirectory => $subdirectory,
813 archive_path => $c->config->{archive_path},
814 archive_filename => $upload_original_name,
815 timestamp => $timestamp,
816 user_id => $user_id,
817 user_role => $c->user->get_object->get_user_type()
819 $archived_filename_with_path = $uploader->archive();
820 $md5 = $uploader->get_md5($archived_filename_with_path);
821 if (!$archived_filename_with_path) {
822 $c->stash->{rest} = {error => "Could not save file $upload_original_name in archive",};
823 return;
825 unlink $upload_tempfile;
827 print STDERR "Check 3: ".localtime()."\n";
829 $upload_metadata{'archived_file'} = $archived_filename_with_path;
830 $upload_metadata{'archived_file_type'}="trial upload file";
831 $upload_metadata{'user_id'}=$user_id;
832 $upload_metadata{'date'}="$timestamp";
834 #parse uploaded file with appropriate plugin
835 $parser = CXGN::Trial::ParseUpload->new(chado_schema => $chado_schema, filename => $archived_filename_with_path);
836 $parser->load_plugin('TrialExcelFormat');
837 $parsed_data = $parser->parse();
839 if (!$parsed_data) {
840 my $return_error = '';
842 if (! $parser->has_parse_errors() ){
843 $return_error = "Could not get parsing errors";
844 $c->stash->{rest} = {error_string => $return_error,};
846 else {
847 $parse_errors = $parser->get_parse_errors();
848 #print STDERR Dumper $parse_errors;
850 foreach my $error_string (@{$parse_errors->{'error_messages'}}){
851 $return_error=$return_error.$error_string."<br>";
855 $c->stash->{rest} = {error_string => $return_error, missing_accessions => $parse_errors->{'missing_accessions'}, missing_seedlots => $parse_errors->{'missing_seedlots'}};
856 return;
859 print STDERR "Check 4: ".localtime()."\n";
861 #print STDERR Dumper $parsed_data;
863 my $save;
864 my $coderef = sub {
866 my %trial_info_hash = (
867 chado_schema => $chado_schema,
868 dbh => $dbh,
869 trial_year => $trial_year,
870 trial_description => $trial_description,
871 trial_location => $trial_location,
872 trial_type => $trial_type,
873 trial_name => $trial_name,
874 user_name => $user_name, #not implemented
875 design_type => $trial_design_method,
876 design => $parsed_data,
877 program => $program,
878 upload_trial_file => $upload,
879 operator => $c->user()->get_object()->get_username(),
880 field_trial_is_planned_to_cross => $field_trial_is_planned_to_cross,
881 field_trial_is_planned_to_be_genotyped => $field_trial_is_planned_to_be_genotyped,
882 field_trial_from_field_trial => $add_project_trial_source_select,
883 genotyping_trial_from_field_trial => $add_project_trial_genotype_trial_select,
884 crossing_trial_from_field_trial => $add_project_trial_crossing_trial_select,
887 if ($field_size){
888 $trial_info_hash{field_size} = $field_size;
890 if ($plot_width){
891 $trial_info_hash{plot_width} = $plot_width;
893 if ($plot_length){
894 $trial_info_hash{plot_length} = $plot_length;
897 my $trial_create = CXGN::Trial::TrialCreate->new(\%trial_info_hash);
898 $save = $trial_create->save_trial();
900 if ($save->{error}){
901 $chado_schema->txn_rollback();
906 try {
907 $chado_schema->txn_do($coderef);
908 } catch {
909 print STDERR "Transaction Error: $_\n";
910 $save->{'error'} = $_;
913 #print STDERR "Check 5: ".localtime()."\n";
914 if ($save->{'error'}) {
915 print STDERR "Error saving trial: ".$save->{'error'};
916 $c->stash->{rest} = {error => $save->{'error'}};
917 return;
918 } elsif ($save->{'trial_id'}) {
920 my $dbh = $c->dbc->dbh();
921 my $bs = CXGN::BreederSearch->new( { dbh=>$dbh, dbname=>$c->config->{dbname}, } );
922 my $refresh = $bs->refresh_matviews($c->config->{dbhost}, $c->config->{dbname}, $c->config->{dbuser}, $c->config->{dbpass}, 'stockprop');
924 $c->stash->{rest} = {success => "1"};
925 return;