upload trial returns error message from TrialCreate when 1 or more arg is not found...
[sgn.git] / lib / SGN / Controller / AJAX / Trial.pm
blobd1d502257e8a5c27c16f6408541512d1979ec9ae
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>
15 Deletion by Lukas
17 =cut
19 package SGN::Controller::AJAX::Trial;
21 use Moose;
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 JSON -support_by_pp;
36 use SGN::View::Trial qw/design_layout_view design_info_view/;
37 use CXGN::Location::LocationLookup;
38 use CXGN::Stock::StockLookup;
39 use CXGN::Trial::TrialLayout;
40 use CXGN::BreedersToolbox::Projects;
41 use CXGN::BreedersToolbox::Delete;
42 use CXGN::UploadFile;
43 use CXGN::Trial::ParseUpload;
44 use CXGN::List::Transform;
45 use SGN::Model::Cvterm;
47 BEGIN { extends 'Catalyst::Controller::REST' }
49 __PACKAGE__->config(
50 default => 'application/json',
51 stash_key => 'rest',
52 map => { 'application/json' => 'JSON', 'text/html' => 'JSON' },
55 has 'schema' => (
56 is => 'rw',
57 isa => 'DBIx::Class::Schema',
58 lazy_build => 1,
61 sub get_trial_layout : Path('/ajax/trial/layout') : ActionClass('REST') { }
63 sub get_trial_layout_POST : Args(0) {
64 my ($self, $c) = @_;
65 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
66 my $project;
67 print STDERR "\n\ntrial layout controller\n";
68 my $trial_layout = CXGN::Trial::TrialLayout->new({schema => $schema, project => $project} );
70 #my $trial_id = $c->req->parm('trial_id');
71 # my $project = $schema->resultset('Project::Project')->find(
72 # {
73 # id => $trial_id,
74 # }
75 # );
79 sub generate_experimental_design : Path('/ajax/trial/generate_experimental_design') : ActionClass('REST') { }
81 sub generate_experimental_design_POST : Args(0) {
82 my ($self, $c) = @_;
83 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
84 my $trial_design = CXGN::Trial::TrialDesign->new();
85 my %design;
86 my %design_info;
87 my $error;
88 my $project_name = $c->req->param('project_name');
89 my $project_description = $c->req->param('project_description');
90 my $year = $c->req->param('year');
91 my @stock_names;
92 my $design_layout_view_html;
93 my $design_info_view_html;
94 if ($c->req->param('stock_list')) {
95 @stock_names = @{_parse_list_from_json($c->req->param('stock_list'))};
96 # my $data = $self->transform_stock_list($c, \@raw_stock_names);
97 # if (exists($data->{missing}) && ref($data->{missing}) && @{$data->{missing}} >0) {
98 # $c->stash->{rest} = { error => "Some stocks were not found. Please edit the list and try again." };
99 # return;
101 # if ($data->{transform} && @{$data->{transform}}>0) {
102 # @stock_names = @{$data->{transform}};
105 my @control_names;
106 if ($c->req->param('control_list')) {
107 @control_names = @{_parse_list_from_json($c->req->param('control_list'))};
110 my $design_type = $c->req->param('design_type');
111 my $rep_count = $c->req->param('rep_count');
112 my $block_number = $c->req->param('block_number');
114 my $row_number = $c->req->param('row_number');
115 my $block_row_number=$c->req->param('row_number_per_block');
116 my $block_col_number=$c->req->param('col_number_per_block');
117 my $col_number =$c->req->param('col_number');
119 my $block_size = $c->req->param('block_size');
120 my $max_block_size = $c->req->param('max_block_size');
121 my $plot_prefix = $c->req->param('plot_prefix');
122 my $start_number = $c->req->param('start_number');
123 my $increment = $c->req->param('increment');
124 my $trial_location = $c->req->param('trial_location');
125 my $trial_name = $c->req->param('project_name');
126 #my $trial_name = "Trial $trial_location $year"; #need to add something to make unique in case of multiple trials in location per year?
130 print STDERR join "\n",$design_type;
131 print STDERR "\n";
133 print STDERR join "\n",$block_number;
134 print STDERR "\n";
136 print STDERR join "\n",$row_number;
137 print STDERR "\n";
141 if (!$c->user()) {
142 $c->stash->{rest} = {error => "You need to be logged in to add a trial" };
143 return;
146 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) { #user must have privileges to add a trial
147 $c->stash->{rest} = {error => "You have insufficient privileges to add a trial." };
148 return;
151 my $geolocation_lookup = CXGN::Location::LocationLookup->new(schema => $schema);
152 $geolocation_lookup->set_location_name($c->req->param('trial_location'));
153 if (!$geolocation_lookup->get_geolocation()){
154 $c->stash->{rest} = { error => "Trial location not found" };
155 return;
158 # my $trial_create = CXGN::Trial::TrialCreate->new(chado_schema => $schema);
159 # $trial_create->set_trial_year($c->req->param('year'));
160 # $trial_create->set_trial_location($c->req->param('trial_location'));
161 # if ($trial_create->trial_name_already_exists()) {
162 # $c->stash->{rest} = {error => "Trial name \"".$trial_create->get_trial_name()."\" already exists" };
163 # return;
166 $trial_design->set_trial_name($trial_name);
168 if (@stock_names) {
169 $trial_design->set_stock_list(\@stock_names);
170 $design_info{'number_of_stocks'} = scalar(@stock_names);
171 } else {
172 $c->stash->{rest} = {error => "No list of stocks supplied." };
173 return;
175 if (@control_names) {
176 $trial_design->set_control_list(\@control_names);
177 $design_info{'number_of_controls'} = scalar(@control_names);
179 if ($start_number) {
180 $trial_design->set_plot_start_number($start_number);
181 } else {
182 $trial_design->set_plot_start_number(1);
184 if ($increment) {
185 $trial_design->set_plot_number_increment($increment);
186 } else {
187 $trial_design->set_plot_number_increment(1);
189 if ($plot_prefix) {
190 $trial_design->set_plot_name_prefix($plot_prefix);
192 if ($rep_count) {
193 $trial_design->set_number_of_reps($rep_count);
195 if ($block_number) {
196 $trial_design->set_number_of_blocks($block_number);
197 #$trial_design->set_number_of_blocks(8);
199 if($row_number){
200 $trial_design->set_number_of_rows($row_number);
201 #$trial_design->set_number_of_rows(9);
203 if($block_row_number){
204 $trial_design->set_block_row_numbers($block_row_number);
205 #$trial_design->set_number_of_rows(9);
207 if($block_col_number){
208 $trial_design->set_block_col_numbers($block_col_number);
209 #$trial_design->set_number_of_rows(9);
211 if($col_number){
212 $trial_design->set_number_of_cols($col_number);
213 #$trial_design->set_number_of_rows(9);
215 if ($block_size) {
216 $trial_design->set_block_size($block_size);
218 if ($max_block_size) {
219 $trial_design->set_maximum_block_size($max_block_size);
221 if ($design_type) {
222 $trial_design->set_design_type($design_type);
223 $design_info{'design_type'} = $design_type;
224 } else {
225 $c->stash->{rest} = {error => "No design type supplied." };
226 return;
228 if (!$trial_design->has_design_type()) {
229 $c->stash->{rest} = {error => "Design type not supported." };
230 return;
234 try {
235 $trial_design->calculate_design();
236 } catch {
237 $c->stash->{rest} = {error => "Could not calculate design: $_"};
238 $error=1;
240 if ($error) {return;}
241 if ($trial_design->get_design()) {
242 %design = %{$trial_design->get_design()};
243 } else {
244 $c->stash->{rest} = {error => "Could not generate design" };
245 return;
247 $design_layout_view_html = design_layout_view(\%design, \%design_info);
248 $design_info_view_html = design_info_view(\%design, \%design_info);
249 my $design_json = encode_json(\%design);
250 $c->stash->{rest} = {
251 success => "1",
252 design_layout_view_html => $design_layout_view_html,
253 design_info_view_html => $design_info_view_html,
254 design_json => $design_json,
258 sub save_experimental_design : Path('/ajax/trial/save_experimental_design') : ActionClass('REST') { }
260 sub save_experimental_design_POST : Args(0) {
261 my ($self, $c) = @_;
262 #my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
263 my $chado_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
264 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema");
265 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema");
266 my $dbh = $c->dbc->dbh;
268 print STDERR "Saving trial... :-)\n";
270 #my $trial_create = new CXGN::Trial::TrialCreate(chado_schema => $schema);
271 if (!$c->user()) {
272 $c->stash->{rest} = {error => "You need to be logged in to add a trial" };
273 return;
275 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) {
276 $c->stash->{rest} = {error => "You have insufficient privileges to add a trial." };
277 return;
279 my $user_id = $c->user()->get_object()->get_sp_person_id();
281 my $user_name = $c->user()->get_object()->get_username();
283 print STDERR "\nUserName: $user_name\n\n";
284 my $error;
286 my $design = _parse_design_from_json($c->req->param('design_json'));
288 my $trial_create = CXGN::Trial::TrialCreate
289 ->new({
290 chado_schema => $chado_schema,
291 phenome_schema => $phenome_schema,
292 dbh => $dbh,
293 user_name => $user_name,
294 design => $design,
295 program => $c->req->param('breeding_program_name'),
296 trial_year => $c->req->param('year'),
297 trial_description => $c->req->param('project_description'),
298 trial_location => $c->req->param('trial_location'),
299 trial_name => $c->req->param('project_name'),
300 design_type => $c->req->param('design_type'),
303 #$trial_create->set_user($c->user()->id());
304 #$trial_create->set_trial_year($c->req->param('year'));
305 #$trial_create->set_trial_location($c->req->param('trial_location'));
306 #$trial_create->set_trial_description($c->req->param('project_description'));
307 #$trial_create->set_design_type($c->req->param('design_type'));
308 #$trial_create->set_breeding_program_id($c->req->param('breeding_program_name'));
309 #$trial_create->set_design(_parse_design_from_json($c->req->param('design_json')));
310 #$trial_create->set_stock_list(_parse_list_from_json($c->req->param('stock_list')));
311 # if ($c->req->param('control_list')) {
312 # $trial_create->set_control_list(_parse_list_from_json($c->req->param('control_list')));
314 if ($trial_create->trial_name_already_exists()) {
315 $c->stash->{rest} = {error => "Trial name \"".$trial_create->get_trial_name()."\" already exists" };
316 return;
319 try {
320 $trial_create->save_trial();
321 } catch {
322 $c->stash->{rest} = {error => "Error saving trial in the database $_"};
323 print STDERR "ERROR SAVING TRIAL!\n";
324 $error = 1;
326 if ($error) {return;}
327 print STDERR "Trial saved successfully\n";
328 $c->stash->{rest} = {success => "1",};
329 return;
332 sub verify_stock_list : Path('/ajax/trial/verify_stock_list') : ActionClass('REST') { }
334 sub verify_stock_list_POST : Args(0) {
335 my ($self, $c) = @_;
336 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
337 my @stock_names;
338 my $error;
339 my %errors;
340 my $error_alert;
341 if ($c->req->param('stock_list')) {
342 @stock_names = @{_parse_list_from_json($c->req->param('stock_list'))};
343 #my $data = $self->transform_stock_list($c, \@raw_stock_names);
344 #if (exists($data->{missing}) && ref($data->{missing}) && @{$data->{missing}} >0) {
345 # $c->stash->{rest} = { error => "Some stocks were not found. Please edit the list and try again." };
346 # return;
348 # if ($data->{transform} && @{$data->{transform}}>0) {
349 # @stock_names = @{$data->{transform}};
353 if (!@stock_names) {
354 $c->stash->{rest} = {error => "No stock names supplied"};
355 return;
359 foreach my $stock_name (@stock_names) {
361 my $stock;
362 my $number_of_stocks_found;
363 my $stock_lookup = CXGN::Stock::StockLookup->new(schema => $schema);
364 $stock_lookup->set_stock_name($stock_name);
365 $stock = $stock_lookup->get_stock();
366 $number_of_stocks_found = $stock_lookup->get_matching_stock_count();
367 if ($number_of_stocks_found > 1) {
368 $errors{$stock_name} = "Multiple stocks found matching $stock_name\n";
370 if (!$number_of_stocks_found) {
371 $errors{$stock_name} = "No stocks found matching $stock_name\n";
374 if (%errors) {
375 foreach my $key (keys %errors) {
376 $error_alert .= "Stock $key: ".$errors{$key}."\n";
378 $c->stash->{rest} = {error => $error_alert};
379 } else {
380 $c->stash->{rest} = {
381 success => "1",
386 sub _parse_list_from_json {
387 my $list_json = shift;
388 my $json = new JSON;
389 if ($list_json) {
390 my $decoded_list = $json->allow_nonref->utf8->relaxed->escape_slash->loose->allow_singlequote->allow_barekey->decode($list_json);
391 #my $decoded_list = decode_json($list_json);
392 my @array_of_list_items = @{$decoded_list};
393 return \@array_of_list_items;
395 else {
396 return;
400 sub _parse_design_from_json {
401 my $design_json = shift;
402 my $json = new JSON;
403 if ($design_json) {
404 my $decoded_json = $json->allow_nonref->utf8->relaxed->escape_slash->loose->allow_singlequote->allow_barekey->decode($design_json);
405 #my $decoded_json = decode_json($design_json);
406 my %design = %{$decoded_json};
407 return \%design;
409 else {
410 return;
414 ###################################################################################
416 sub upload_trial_file : Path('/ajax/trial/upload_trial_file') : ActionClass('REST') { }
418 sub upload_trial_file_POST : Args(0) {
419 my ($self, $c) = @_;
421 print STDERR "Check 1: ".localtime();
423 my $chado_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
424 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema");
425 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema");
426 my $dbh = $c->dbc->dbh;
427 my $program = $c->req->param('trial_upload_breeding_program');
428 my $trial_location = $c->req->param('trial_upload_location');
429 my $trial_name = $c->req->param('trial_upload_name');
430 my $trial_year = $c->req->param('trial_upload_year');
431 my $trial_description = $c->req->param('trial_upload_description');
432 my $trial_design_method = $c->req->param('trial_upload_design_method');
433 my $upload = $c->req->upload('trial_uploaded_file');
434 my $uploader = CXGN::UploadFile->new();
435 my $parser;
436 my $parsed_data;
437 my $upload_original_name = $upload->filename();
438 my $upload_tempfile = $upload->tempname;
439 my $subdirectory = "trial_upload";
440 my $archived_filename_with_path;
441 my $md5;
442 my $validate_file;
443 my $parsed_file;
444 my $parse_errors;
445 my %parsed_data;
446 my %upload_metadata;
447 my $time = DateTime->now();
448 my $timestamp = $time->ymd()."_".$time->hms();
449 my $user_id;
450 my $user_name;
451 my $error;
453 print STDERR "Check 2: ".localtime();
455 if (!$c->user()) {
456 print STDERR "User not logged in... not adding a crosses.\n";
457 $c->stash->{rest} = {error => "You need to be logged in to add a cross." };
458 return;
460 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) {
461 $c->stash->{rest} = {error => "You have insufficient privileges to add a trial." };
462 return;
465 $user_id = $c->user()->get_object()->get_sp_person_id();
467 $user_name = $c->user()->get_object()->get_username();
469 ## Store uploaded temporary file in archive
470 $archived_filename_with_path = $uploader->archive($c, $subdirectory, $upload_tempfile, $upload_original_name, $timestamp);
471 $md5 = $uploader->get_md5($archived_filename_with_path);
472 if (!$archived_filename_with_path) {
473 $c->stash->{rest} = {error => "Could not save file $upload_original_name in archive",};
474 return;
476 unlink $upload_tempfile;
478 print STDERR "Check 3: ".localtime();
480 $upload_metadata{'archived_file'} = $archived_filename_with_path;
481 $upload_metadata{'archived_file_type'}="trial upload file";
482 $upload_metadata{'user_id'}=$user_id;
483 $upload_metadata{'date'}="$timestamp";
485 #parse uploaded file with appropriate plugin
486 $parser = CXGN::Trial::ParseUpload->new(chado_schema => $chado_schema, filename => $archived_filename_with_path);
487 $parser->load_plugin('TrialExcelFormat');
488 $parsed_data = $parser->parse();
490 if (!$parsed_data) {
491 my $return_error = '';
493 if (! $parser->has_parse_errors() ){
494 $return_error = "Could not get parsing errors";
495 $c->stash->{rest} = {error_string => $return_error,};
498 else {
499 $parse_errors = $parser->get_parse_errors();
500 foreach my $error_string (@{$parse_errors}){
501 $return_error=$return_error.$error_string."<br>";
505 $c->stash->{rest} = {error_string => $return_error,};
506 return;
509 print STDERR "Check 4: ".localtime();
511 my $trial_create = CXGN::Trial::TrialCreate
512 ->new({
513 chado_schema => $chado_schema,
514 phenome_schema => $phenome_schema,
515 dbh => $dbh,
516 trial_year => $trial_year,
517 trial_description => $trial_description,
518 trial_location => $trial_location,
519 trial_name => $trial_name,
520 user_name => $user_name, #not implemented
521 design_type => $trial_design_method,
522 design => $parsed_data,
523 program => $program,
524 upload_trial_file => $upload,
527 try {
528 $trial_create->save_trial();
529 } catch {
530 $c->stash->{rest} = {error => "Error saving trial in the database $_"};
531 $error = 1;
534 print STDERR "Check 5: ".localtime();
536 if ($error) {return;}
537 $c->stash->{rest} = {success => "1",};
538 return;
545 ###################################################################################
546 ##remove this soon. using above instead
547 sub upload_trial_layout : Path('/trial/upload_trial_layout') : ActionClass('REST') { }
549 sub upload_trial_layout_POST : Args(0) {
550 my ($self, $c) = @_;
551 my @contents;
552 my $error = 0;
553 my $upload = $c->req->upload('trial_upload_file');
554 my $header_line;
555 my @header_contents;
556 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
557 if (!$c->user()) { #user must be logged in
558 $c->stash->{rest} = {error => "You need to be logged in to upload a file." };
559 return;
561 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) { #user must have privileges to add a trial
562 $c->stash->{rest} = {error => "You have insufficient privileges to upload a file." };
563 return;
565 if (!$upload) { #upload file required
566 $c->stash->{rest} = {error => "File upload failed: no file name received"};
567 return;
569 try { #get file contents
570 @contents = split /\n/, $upload->slurp;
571 } catch {
572 $c->stash->{rest} = {error => "File upload failed: $_"};
573 $error = 1;
575 if ($error) {return;}
576 if (@contents < 2) { #upload file must contain at least one line of data plus a header
577 $c->stash->{rest} = {error => "File upload failed: contains less than two lines"};
578 return;
580 $header_line = shift(@contents);
581 @header_contents = split /\t/, $header_line;
582 try { #verify header contents
583 _verify_trial_layout_header(\@header_contents);
584 } catch {
585 $c->stash->{rest} = {error => "File upload failed: $_"};
586 $error = 1;
588 if ($error) {return;}
590 #verify location
591 if (! $schema->resultset("NaturalDiversity::NdGeolocation")->find({description=>$c->req->param('add_project_location'),})){
592 $c->stash->{rest} = {error => "File upload failed: location not found"};
593 return;
596 try { #verify contents of file
597 _verify_trial_layout_contents($self, $c, \@contents);
598 } catch {
599 my %error_hash = %{$_};
600 #my $error_string = Dumper(%error_hash);
601 my $error_string = _formatted_string_from_error_hash(\%error_hash);
602 $c->stash->{rest} = {error => "File upload failed: missing or invalid content (see details that follow..)", error_string => "$error_string"};
603 $error = 1;
605 if ($error) {return;}
607 try { #add file contents to the database
608 _add_trial_layout_to_database($self,$c,\@contents);
609 } catch {
610 $c->stash->{rest} = {error => "File upload failed: $_"};
613 if ($error) {
614 return;
615 } else {
616 $c->stash->{rest} = {success => "1"};
620 sub _add_trial_layout_to_database {
621 my $self = shift;
622 my $c = shift;
623 my $contents_ref = shift;
624 my @contents = @{$contents_ref};
625 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
626 my $year = $c->req->param('add_project_year');
627 my $location = $c->req->param('add_project_location');
628 my $project_name = $c->req->param('add_project_name');
629 my $project_description = $c->req->param('add_project_description');
630 my $plot_cvterm = SGN::Model::Cvterm->get_cvterm_row($schema, 'plot', 'stock_type');
631 my $geolocation = $schema->resultset("NaturalDiversity::NdGeolocation")
632 ->find_or_create({
633 description => $location, #add this as an option
635 my $organism = $schema->resultset("Organism::Organism")
636 ->find_or_create({
637 genus => 'Manihot',
638 species => 'Manihot esculenta',
641 #this is wrong. Does not seem to be used in the database !!
642 my $plot_exp_cvterm = SGN::Model::Cvterm->get_cvterm_row($schema, 'plot_experiment', 'experiment_type');
645 #create project
646 my $project = $schema->resultset('Project::Project')
647 ->find_or_create({
648 name => $project_name,
649 description => $location,
653 my $projectprop_year = $project->create_projectprops( { 'project year' => $year,}, {autocreate=>1});
654 my $organism_id = $organism->organism_id();
656 foreach my $content_line (@contents) {
657 my @line_contents = split /\t/, $content_line;
658 my $plot_name = $line_contents[0];
659 my $block_number = $line_contents[1];
660 my $rep_number = $line_contents[2];
661 my $stock_name = $line_contents[3];
662 my $stock;
663 my $stock_rs = $schema->resultset("Stock::Stock")
664 ->search({
665 -or => [
666 'lower(me.uniquename)' => { like => lc($stock_name) },
667 -and => [
668 'lower(type.name)' => { like => '%synonym%' },
669 'lower(stockprops.value)' => { like => lc($stock_name) },
674 join => { 'stockprops' => 'type'} ,
675 distinct => 1
678 if ($stock_rs->count >1 ) {
679 die ("multiple stocks found matching $stock_name");
680 } elsif ($stock_rs->count == 1) {
681 $stock = $stock_rs->first;
682 } else {
683 die ("no stocks found matching $stock_name");
685 my $unique_plot_name =
686 $project_name."_".$stock_name."_plot_".$plot_name."_block_".$block_number."_rep_".$rep_number."_".$year."_".$location;
687 my $plot = $schema->resultset("Stock::Stock")
688 ->find_or_create({
689 organism_id => $stock->organism_id(),
690 name => $unique_plot_name,
691 uniquename => $unique_plot_name,
692 type_id => $plot_cvterm->cvterm_id,
694 my $experiment = $schema->resultset('NaturalDiversity::NdExperiment')
695 ->create({
696 nd_geolocation_id => $geolocation->nd_geolocation_id(),
697 type_id => $plot_exp_cvterm->cvterm_id(),
699 #link to the project
700 $experiment
701 ->find_or_create_related('nd_experiment_projects',{
702 project_id => $project->project_id()
704 #link the experiment to the stock
705 $experiment
706 ->find_or_create_related('nd_experiment_stocks' ,{
707 stock_id => $plot->stock_id(),
708 type_id => $plot_exp_cvterm->cvterm_id(),
713 sub _verify_trial_layout_header {
714 my $header_content_ref = shift;
715 my @header_contents = @{$header_content_ref};
716 if ($header_contents[0] ne 'plot_name' ||
717 $header_contents[1] ne 'block_number' ||
718 $header_contents[2] ne 'rep_number' ||
719 $header_contents[3] ne 'stock_name') {
720 die ("Wrong column names in header\n");
722 if (@header_contents != 4) {
723 die ("Wrong number of columns in header\n");
725 return;
728 sub _verify_trial_layout_contents {
729 my $self = shift;
730 my $c = shift;
731 my $contents_ref = shift;
732 my @contents = @{$contents_ref};
733 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
734 my $year = $c->req->param('add_project_year');
735 my $location = $c->req->param('add_project_location');
736 my $project_name = $c->req->param('add_project_name');
737 my $line_number = 1;
738 my %error_hash;
739 my %plot_name_errors;
740 my %block_number_errors;
741 my %rep_number_errors;
742 my %stock_name_errors;
743 my %column_number_errors;
744 foreach my $content_line (@contents) {
745 my @line_contents = split /\t/, $content_line;
746 if (@line_contents != 4) {
747 my $column_count = scalar(@line_contents);
748 $column_number_errors{$line_number} = "Line $line_number: wrong number of columns, expected 4, found $column_count";
749 $line_number++;
750 next;
752 my $plot_name = $line_contents[0];
753 my $block_number = $line_contents[1];
754 my $rep_number = $line_contents[2];
755 my $stock_name = $line_contents[3];
756 if (!$stock_name) {
757 $stock_name_errors{$line_number} = "Line $line_number: stock name is missing";
758 } else {
759 #make sure stock name exists and returns a unique result
760 my $stock_rs = $schema->resultset("Stock::Stock")
761 ->search({
762 -or => [
763 'lower(me.uniquename)' => { like => lc($stock_name) },
764 -and => [
765 'lower(type.name)' => { like => '%synonym%' },
766 'lower(stockprops.value)' => { like => lc($stock_name) },
771 join => { 'stockprops' => 'type'} ,
772 distinct => 1
775 if ($stock_rs->count >1 ) {
776 my $error_string = "Line $line_number: multiple accessions found for stock name $stock_name (";
777 while ( my $st = $stock_rs->next) {
778 my $error_string .= $st->uniquename.",";
780 $stock_name_errors{$line_number} = $error_string;
781 } elsif ($stock_rs->count == 1) {
782 } else {
783 $stock_name_errors{$line_number} = "Line $line_number: stock name $stock_name not found";
787 if (!$plot_name) {
788 $plot_name_errors{$line_number} = "Line $line_number: plot name is missing";
789 } else {
790 my $unique_plot_name = $project_name."_".$stock_name."_plot_".$plot_name."_block_".$block_number."_rep_".$rep_number."_".$year."_".$location;
791 if ($schema->resultset("Stock::Stock")->find({uniquename=>$unique_plot_name,})) {
792 $plot_name_errors{$line_number} = "Line $line_number: plot name $unique_plot_name is not unique";
796 #check for valid block number
797 if (!$block_number) {
798 $block_number_errors{$line_number} = "Line $line_number: block number is missing";
799 } else {
800 if (!($block_number =~ /^\d+?$/)) {
801 $block_number_errors{$line_number} = "Line $line_number: block number $block_number is not an integer";
802 } elsif ($block_number < 1 || $block_number > 1000000) {
803 $block_number_errors{$line_number} = "Line $line_number: block number $block_number is out of range";
807 #check for valid rep number
808 if (!$rep_number) {
809 $rep_number_errors{$line_number} = "Line $line_number: rep number is missing";
810 } else {
811 if (!($rep_number =~ /^\d+?$/)) {
812 $rep_number_errors{$line_number} = "Line $line_number: rep number $rep_number is not an integer";
813 } elsif ($rep_number < 1 || $rep_number > 1000000) {
814 $rep_number_errors{$line_number} = "Line $line_number: rep number $block_number is out of range";
817 $line_number++;
820 if (%plot_name_errors) {$error_hash{'plot_name_errors'}=\%plot_name_errors;}
821 if (%block_number_errors) {$error_hash{'block_number_errors'}=\%block_number_errors;}
822 if (%rep_number_errors) {$error_hash{'rep_number_errors'}=\%rep_number_errors;}
823 if (%stock_name_errors) {$error_hash{'stock_name_errors'}=\%stock_name_errors;}
824 if (%column_number_errors) {$error_hash{'column_number_errors'}=\%column_number_errors;}
825 if (%error_hash) {
826 die (\%error_hash);
828 return;
831 sub _formatted_string_from_error_hash {
832 my $error_hash_ref = shift;
833 my %error_hash = %{$error_hash_ref};
834 my $error_string ;
835 if ($error_hash{column_number_errors}) {
836 $error_string .= "<b>Column number errors</b><br><br>"._formatted_string_from_error_hash_by_type(\%{$error_hash{column_number_errors}})."<br><br>";
838 if ($error_hash{stock_name_errors}) {
839 $error_string .= "<b>Stock name errors</b><br><br>"._formatted_string_from_error_hash_by_type(\%{$error_hash{stock_name_errors}})."<br><br>";
841 if ($error_hash{'plot_name_errors'}) {
842 $error_string .= "<b>Plot name errors</b><br><br>"._formatted_string_from_error_hash_by_type(\%{$error_hash{'plot_name_errors'}})."<br><br>";
844 if ($error_hash{'block_number_errors'}) {
845 $error_string .= "<b>Block number errors</b><br><br>"._formatted_string_from_error_hash_by_type(\%{$error_hash{'block_number_errors'}})."<br><br>";
847 if ($error_hash{'rep_number_errors'}) {
848 $error_string .= "<b>Rep number errors</b><br><br>"._formatted_string_from_error_hash_by_type(\%{$error_hash{'rep_number_errors'}})."<br><br>";
850 return $error_string;
853 sub _formatted_string_from_error_hash_by_type {
854 my $error_hash_ref = shift;
855 my %error_hash = %{$error_hash_ref};
856 my $error_string;
857 foreach my $key (sort { $a <=> $b} keys %error_hash) {
858 $error_string .= $error_hash{$key} . "<br>";
860 return $error_string;
864 ### The following was moved to TrialMetadata.
865 # sub trial : Chained('/') PathPart('ajax/breeders/trial') CaptureArgs(1) {
866 # my $self = shift;
867 # my $c = shift;
868 # my $trial_id = shift;
870 # print STDERR "TRIAL ID: $trial_id\n";
871 # $c->stash->{trial_id} = $trial_id;
872 # $c->stash->{trial} = CXGN::Trial->new( { bcs_schema => $c->dbic_schema("Bio::Chado::Schema"), trial_id => $trial_id });
874 # if (!$c->stash->{trial}) {
875 # $c->stash->{rest} = { error => "The specified trial with id $trial_id does not exist" };
876 # return;
882 # =head2 delete_trial_by_file
884 # Usage:
885 # Desc:
886 # Ret:
887 # Args:
888 # Side Effects:
889 # Example:
891 # =cut
893 # sub delete_trial_by_file : Path('/breeders/trial/delete/file') Args(1) {
894 # my $self = shift;
895 # my $c = shift;
897 # my $file_id = shift;
899 # if (!$c->user()) {
900 # $c->stash->{rest} = { error => 'You must be logged in to delete a trial' };
901 # return;
904 # if (! ($c->user->check_roles('curator') || $c->user->check_roles('submitter'))) {
905 # $c->stash->{rest} = { error => 'You do not have sufficient privileges to delete a trial.' };
908 # my $del = CXGN::BreedersToolbox::Delete->new(
909 # bcs_schema => $c->dbic_schema("Bio::Chado::Schema"),
910 # metadata_schema => $c->dbic_schema("CXGN::Metadata::Schema"),
911 # phenome_schema => $c->dbic_schema("CXGN::Phenome::Schema"),
912 # );
914 # if ($del->delete_experiments_by_file($c->user->get_object()->get_sp_person_id(), $file_id)) {
915 # $c->stash->{rest} = { success => 1 };
917 # else {
918 # $c->stash->{rest} = { error => "The trial information could not be removed from the database." };
919 # }
923 # =head2 delete_trial_by_trial_id
925 # Usage:
926 # Desc: Deletes plots associated with a phenotyping experiment
927 # Ret:
928 # Args:
929 # Side Effects:
930 # Example:
932 # =cut
934 # sub delete_trial_by_trial_id : Path('/breeders/trial/delete/id') Args(1) {
935 # my $self = shift;
936 # my $c = shift;
938 # my $trial_id = shift;
940 # print STDERR "DELETING trial $trial_id\n";
942 # if (!$c->user()) {
943 # $c->stash->{rest} = { error => 'You must be logged in to delete a trial' };
944 # return;
947 # my $user_id = $c->user->get_object()->get_sp_person_id();
949 # my $schema = $c->dbic_schema("Bio::Chado::Schema");
951 # my $breeding_program_rs = $schema->resultset("Cv::Cvterm")->search( { name => "breeding_program" });
953 # my $breeding_program_id = $breeding_program_rs->first()->cvterm_id();
955 # my $breeding_program_name = $breeding_program_rs->first()->name();
957 # my $trial_organization_id = $schema->resultset("Project::Projectprop")->search(
958 # {
959 # project_id => $trial_id,
960 # type_id=>$breeding_program_id
961 # });
963 # if (! ($c->user->check_roles('curator') || ( $c->user->check_roles('submitter') && $c->roles($breeding_program_name) ))) {
964 # $c->stash->{rest} = { error => 'You do not have sufficient privileges to delete a trial.' };
967 # # my $del = CXGN::BreedersToolbox::Delete->new(
968 # # bcs_schema => $c->dbic_schema("Bio::Chado::Schema"),
969 # # metadata_schema => $c->dbic_schema("CXGN::Metadata::Schema"),
970 # # phenome_schema => $c->dbic_schema("CXGN::Phenome::Schema"),
971 # # );
973 # my $t = CXGN::Trial->new( { trial_id=> $trial_id, bcs_schema => $c->dbic_schema("Bio::Chado::Schema") });
975 # my $hash = $t->delete_experiments($user_id, $trial_id);
977 # $c->stash->{rest} = $hash;
981 # =head2 delete_phenotype_data_by_trial_id
983 # Usage:
984 # Desc:
985 # Ret:
986 # Args:
987 # Side Effects:
988 # Example:
990 # =cut
992 # sub delete_phenotype_data_by_trial_id : Path('/breeders/trial/phenotype/delete/id') Args(1) {
993 # my $self = shift;
994 # my $c = shift;
996 # my $trial_id = shift;
998 # print STDERR "DELETING phenotypes of trial $trial_id\n";
1000 # if (!$c->user()) {
1001 # $c->stash->{rest} = { error => 'You must be logged in to delete a trial' };
1002 # return;
1005 # my $user_id = $c->user->get_object()->get_sp_person_id();
1007 # my $schema = $c->dbic_schema("Bio::Chado::Schema");
1009 # my $breeding_program_rs = $schema->resultset("Cv::Cvterm")->search( { name => "breeding_program" });
1011 # my $breeding_program_id = $breeding_program_rs->first()->cvterm_id();
1013 # my $breeding_program_name = $breeding_program_rs->first()->name();
1015 # my $trial_organization_id = $schema->resultset("Project::Projectprop")->search(
1016 # {
1017 # project_id => $trial_id,
1018 # type_id=>$breeding_program_id
1019 # });
1021 # if (! ($c->user->check_roles('curator') || ( $c->user->check_roles('submitter') && $c->roles($breeding_program_name) ))) {
1022 # $c->stash->{rest} = { error => 'You do not have sufficient privileges to delete a trial.' };
1025 # my $t = CXGN::Trial->new( { trial_id => $trial_id, bcs_schema => $c->dbic_schema("Bio::Chado::Schema") });
1027 # my $error = $t->delete_metadata($c->dbic_schema("CXGN::Metadata::Schema"), $c->dbic_schema("CXGN::Phenome::Schema"));
1029 # print STDERR "ERROR DELETING METADATA: $error\n";
1030 # my $error = $t->delete_phenotype_data($trial_id);
1032 # print STDERR "ERROR DELETING PHENOTYPES: $error\n";
1033 # if ($error) {
1034 # $c->stash->{rest} = { error => $error };
1036 # else {
1037 # $c->stash->{rest} = { success => "1" };
1041 # =head2 delete_trial_layout_by_trial_id
1043 # Usage:
1044 # Desc:
1045 # Ret:
1046 # Args:
1047 # Side Effects:
1048 # Example:
1050 # =cut
1052 # sub delete_trial_layout_by_trial_id : Path('/breeders/trial/layout/delete/id') Args(1) {
1053 # my $self = shift;
1054 # my $c = shift;
1056 # my $trial_id = shift;
1058 # print STDERR "DELETING trial layout $trial_id\n";
1060 # if (!$c->user()) {
1061 # $c->stash->{rest} = { error => 'You must be logged in to delete a trial layout' };
1062 # return;
1065 # my $user_id = $c->user->get_object()->get_sp_person_id();
1067 # my $schema = $c->dbic_schema("Bio::Chado::Schema");
1069 # my $breeding_program_rs = $schema->resultset("Cv::Cvterm")->search( { name => "breeding_program" });
1071 # my $breeding_program_id = $breeding_program_rs->first()->cvterm_id();
1073 # my $breeding_program_name = $breeding_program_rs->first()->name();
1075 # my $trial_organization_id = $schema->resultset("Project::Projectprop")->search(
1076 # {
1077 # project_id => $trial_id,
1078 # type_id=>$breeding_program_id
1079 # });
1081 # if (! ($c->user->check_roles('curator') || ( $c->user->check_roles('submitter') && $c->roles($breeding_program_name) ))) {
1082 # $c->stash->{rest} = { error => 'You do not have sufficient privileges to delete a trial.' };
1085 # #my $del = CXGN::BreedersToolbox::Delete->new(
1086 # # bcs_schema => $c->dbic_schema("Bio::Chado::Schema"),
1087 # # metadata_schema => $c->dbic_schema("CXGN::Metadata::Schema"),
1088 # # phenome_schema => $c->dbic_schema("CXGN::Phenome::Schema"),
1089 # # );
1091 # my $t = CXGN::Trial->new( { bcs_schema => $c->dbic_schema("Bio::Chado::Schema"), trial_id => $trial_id });
1092 # #my $error = $del->delete_field_layout_by_trial($trial_id);
1094 # my $error = $t->delete_field_layout();
1095 # if ($error) {
1096 # $c->stash->{rest} = { error => $error };
1098 # $c->stash->{rest} = { success => 1 };
1104 # sub trial_description : Local() ActionClass('REST');
1106 # sub trial_description_GET : Chained('trial') PathPart('description') Args(0) {
1107 # my $self = shift;
1108 # my $c = shift;
1110 # my $trial = $c->stash->{trial};
1112 # print STDERR "TRIAL: ".$trial->get_description()."\n";
1114 # $c->stash->{rest} = { description => $trial->get_description() };
1118 # sub trial_description_POST : Chained('trial') PathPart('description') Args(1) {
1119 # my $self = shift;
1120 # my $c = shift;
1121 # my $description = shift;
1123 # if (!($c->user()->check_roles('curator') || $c->user()->check_roles('submitter'))) {
1124 # $c->stash->{rest} = { error => 'You do not have the required privileges to edit the trial type of this trial.' };
1125 # return;
1128 # my $trial_id = $c->stash->{trial_id};
1129 # my $trial = $c->stash->{trial};
1131 # my $p = CXGN::BreedersToolbox::Projects->new( { schema => $c->dbic_schema("Bio::Chado::Schema") });
1133 # my $breeding_program = $p->get_breeding_programs_by_trial($trial_id);
1135 # if (! ($c->user() && ($c->user->check_roles("curator") || $c->user->check_roles($breeding_program)))) {
1136 # $c->stash->{rest} = { error => "You need to be logged in with sufficient privileges to change the description of a trial." };
1137 # return;
1140 # $trial->set_description($description);
1142 # $c->stash->{rest} = { success => 1 };
1145 # # sub get_trial_type :Path('/ajax/breeders/trial/type') Args(1) {
1146 # # my $self = shift;
1147 # # my $c = shift;
1148 # # my $trial_id = shift;
1150 # # my $t = CXGN::Trial->new( { bcs_schema => $c->dbic_schema("Bio::Chado::Schema"), trial_id => $trial_id } );
1152 # # $c->stash->{rest} = { type => $t->get_project_type() };
1154 # # }
1157 # sub trial_location : Local() ActionClass('REST');
1159 # sub trial_location_GET : Chained('trial') PathPart('location') Args(0) {
1160 # my $self = shift;
1161 # my $c = shift;
1163 # my $t = $c->stash->{trial};
1165 # $c->stash->{rest} = { location => [ $t->get_location()->[0], $t->get_location()->[1] ] };
1169 # sub trial_location_POST : Chained('trial') PathPart('location') Args(1) {
1170 # my $self = shift;
1171 # my $c = shift;
1172 # my $location_id = shift;
1174 # if (!($c->user()->check_roles('curator') || $c->user()->check_roles('submitter'))) {
1175 # $c->stash->{rest} = { error => 'You do not have the required privileges to edit the trial type of this trial.' };
1176 # return;
1179 # print STDERR "trial location POST!\n";
1181 # #my $location_id = $c->req->param("location_id");
1183 # my $t = $c->stash->{trial};
1184 # my $trial_id = $c->stash->{trial_id};
1186 # # remove old location
1188 # $t->remove_location($t->get_location()->[0]);
1190 # # add new one
1192 # $t->add_location($location_id);
1194 # $c->stash->{rest} = { message => "Successfully stored location for trial $trial_id",
1195 # trial_id => $trial_id };
1199 # sub trial_year : Local() ActionClass('REST');
1201 # sub trial_year_GET : Chained('trial') PathPart('year') Args(0) {
1202 # my $self = shift;
1203 # my $c = shift;
1205 # my $t = $c->stash->{trial};
1207 # $c->stash->{rest} = { year => $t->get_year() };
1211 # sub trial_year_POST : Chained('trial') PathPart('year') Args(1) {
1212 # my $self = shift;
1213 # my $c = shift;
1214 # my $year = shift;
1216 # if (!($c->user()->check_roles('curator') || $c->user()->check_roles('submitter'))) {
1217 # $c->stash->{rest} = { error => 'You do not have the required privileges to edit the trial type of this trial.' };
1218 # return;
1221 # my $t = $c->stash->{trial};
1223 # $t->set_year($year);
1225 # $c->stash->{rest} = { message => "Year set successfully" };
1228 # sub trial_type : Local() ActionClass('REST');
1230 # sub trial_type_GET : Chained('trial') PathPart('type') Args(0) {
1231 # my $self = shift;
1232 # my $c = shift;
1234 # my $t = $c->stash->{trial};
1236 # my $type = $t->get_project_type();
1237 # $c->stash->{rest} = { type => $type };
1240 # sub trial_type_POST : Chained('trial') PathPart('type') Args(1) {
1241 # my $self = shift;
1242 # my $c = shift;
1243 # my $type = shift;
1245 # if (!($c->user()->check_roles('curator') || $c->user()->check_roles('submitter'))) {
1246 # $c->stash->{rest} = { error => 'You do not have the required privileges to edit the trial type of this trial.' };
1247 # return;
1250 # my $t = $c->stash->{trial};
1251 # my $trial_id = $c->stash->{trial_id};
1253 # # remove previous associations
1255 # $t->dissociate_project_type();
1257 # # set the new trial type
1259 # $t->associate_project_type($type);
1261 # $c->stash->{rest} = { success => 1 };