clean
[sgn.git] / lib / SGN / Controller / AJAX / Trial.pm
blob316234760f14c1d3f1d262ced9cb53c92e958f18
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;
46 use JSON;
48 BEGIN { extends 'Catalyst::Controller::REST' }
50 __PACKAGE__->config(
51 default => 'application/json',
52 stash_key => 'rest',
53 map => { 'application/json' => 'JSON', 'text/html' => 'JSON' },
56 has 'schema' => (
57 is => 'rw',
58 isa => 'DBIx::Class::Schema',
59 lazy_build => 1,
62 sub get_trial_layout : Path('/ajax/trial/layout') : ActionClass('REST') { }
64 sub get_trial_layout_POST : Args(0) {
65 my ($self, $c) = @_;
66 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
67 my $project;
68 print STDERR "\n\ntrial layout controller\n";
69 my $trial_layout = CXGN::Trial::TrialLayout->new({schema => $schema, project => $project} );
71 #my $trial_id = $c->req->parm('trial_id');
72 # my $project = $schema->resultset('Project::Project')->find(
73 # {
74 # id => $trial_id,
75 # }
76 # );
80 sub generate_experimental_design : Path('/ajax/trial/generate_experimental_design') : ActionClass('REST') { }
82 sub generate_experimental_design_POST : Args(0) {
83 my ($self, $c) = @_;
84 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
85 my $trial_design = CXGN::Trial::TrialDesign->new();
86 my %design;
87 my %design_info;
88 my $error;
89 my $project_name = $c->req->param('project_name');
90 my $project_description = $c->req->param('project_description');
91 my $year = $c->req->param('year');
92 my @stock_names;
93 my $design_layout_view_html;
94 my $design_info_view_html;
95 if ($c->req->param('stock_list')) {
96 @stock_names = @{_parse_list_from_json($c->req->param('stock_list'))};
97 # my $data = $self->transform_stock_list($c, \@raw_stock_names);
98 # if (exists($data->{missing}) && ref($data->{missing}) && @{$data->{missing}} >0) {
99 # $c->stash->{rest} = { error => "Some stocks were not found. Please edit the list and try again." };
100 # return;
102 # if ($data->{transform} && @{$data->{transform}}>0) {
103 # @stock_names = @{$data->{transform}};
106 my @control_names;
107 if ($c->req->param('control_list')) {
108 @control_names = @{_parse_list_from_json($c->req->param('control_list'))};
111 my @control_names_crbd;
112 if ($c->req->param('control_list_crbd')) {
113 @control_names_crbd = @{_parse_list_from_json($c->req->param('control_list_crbd'))};
116 my $design_type = $c->req->param('design_type');
117 my $rep_count = $c->req->param('rep_count');
118 my $block_number = $c->req->param('block_number');
120 my $row_number = $c->req->param('row_number');
121 my $block_row_number=$c->req->param('row_number_per_block');
122 my $block_col_number=$c->req->param('col_number_per_block');
123 my $col_number =$c->req->param('col_number');
125 my $block_size = $c->req->param('block_size');
126 my $max_block_size = $c->req->param('max_block_size');
127 my $plot_prefix = $c->req->param('plot_prefix');
128 my $start_number = $c->req->param('start_number');
129 my $increment = $c->req->param('increment');
130 my $trial_location = $c->req->param('trial_location');
131 my $trial_name = $c->req->param('project_name');
132 my $greenhouse_num_plants = $c->req->param('greenhouse_num_plants');
133 #my $trial_name = "Trial $trial_location $year"; #need to add something to make unique in case of multiple trials in location per year?
134 if ($design_type eq "RCBD" || $design_type eq "Alpha") {
135 if (@control_names_crbd) {
136 @stock_names = (@stock_names, @control_names_crbd);
140 print STDERR join "\n",$design_type;
141 print STDERR "\n";
143 print STDERR join "\n",$block_number;
144 print STDERR "\n";
146 print STDERR join "\n",$row_number;
147 print STDERR "\n";
151 if (!$c->user()) {
152 $c->stash->{rest} = {error => "You need to be logged in to add a trial" };
153 return;
156 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) { #user must have privileges to add a trial
157 $c->stash->{rest} = {error => "You have insufficient privileges to add a trial." };
158 return;
161 my $geolocation_lookup = CXGN::Location::LocationLookup->new(schema => $schema);
162 $geolocation_lookup->set_location_name($c->req->param('trial_location'));
163 if (!$geolocation_lookup->get_geolocation()){
164 $c->stash->{rest} = { error => "Trial location not found" };
165 return;
168 # my $trial_create = CXGN::Trial::TrialCreate->new(chado_schema => $schema);
169 # $trial_create->set_trial_year($c->req->param('year'));
170 # $trial_create->set_trial_location($c->req->param('trial_location'));
171 # if ($trial_create->trial_name_already_exists()) {
172 # $c->stash->{rest} = {error => "Trial name \"".$trial_create->get_trial_name()."\" already exists" };
173 # return;
176 $trial_design->set_trial_name($trial_name);
178 if (@stock_names) {
179 $trial_design->set_stock_list(\@stock_names);
180 $design_info{'number_of_stocks'} = scalar(@stock_names);
181 } else {
182 $c->stash->{rest} = {error => "No list of stocks supplied." };
183 return;
185 if (@control_names) {
186 $trial_design->set_control_list(\@control_names);
187 $design_info{'number_of_controls'} = scalar(@control_names);
189 if (@control_names_crbd) {
190 $trial_design->set_control_list_crbd(\@control_names_crbd);
191 $design_info{'number_of_controls_crbd'} = scalar(@control_names_crbd);
193 if ($start_number) {
194 $trial_design->set_plot_start_number($start_number);
195 } else {
196 $trial_design->set_plot_start_number(1);
198 if ($increment) {
199 $trial_design->set_plot_number_increment($increment);
200 } else {
201 $trial_design->set_plot_number_increment(1);
203 if ($plot_prefix) {
204 $trial_design->set_plot_name_prefix($plot_prefix);
206 if ($rep_count) {
207 $trial_design->set_number_of_reps($rep_count);
209 if ($block_number) {
210 $trial_design->set_number_of_blocks($block_number);
211 #$trial_design->set_number_of_blocks(8);
213 if($row_number){
214 $trial_design->set_number_of_rows($row_number);
215 #$trial_design->set_number_of_rows(9);
217 if($block_row_number){
218 $trial_design->set_block_row_numbers($block_row_number);
219 #$trial_design->set_number_of_rows(9);
221 if($block_col_number){
222 $trial_design->set_block_col_numbers($block_col_number);
223 #$trial_design->set_number_of_rows(9);
225 if($col_number){
226 $trial_design->set_number_of_cols($col_number);
227 #$trial_design->set_number_of_rows(9);
229 if ($block_size) {
230 $trial_design->set_block_size($block_size);
232 if ($max_block_size) {
233 $trial_design->set_maximum_block_size($max_block_size);
235 if ($greenhouse_num_plants) {
236 my $json = JSON->new();
237 $trial_design->set_greenhouse_num_plants($json->decode($greenhouse_num_plants));
239 if ($design_type) {
240 $trial_design->set_design_type($design_type);
241 $design_info{'design_type'} = $design_type;
242 } else {
243 $c->stash->{rest} = {error => "No design type supplied." };
244 return;
246 if (!$trial_design->has_design_type()) {
247 $c->stash->{rest} = {error => "Design type not supported." };
248 return;
252 try {
253 $trial_design->calculate_design();
254 } catch {
255 $c->stash->{rest} = {error => "Could not calculate design: $_"};
256 $error=1;
258 if ($error) {return;}
259 if ($trial_design->get_design()) {
260 %design = %{$trial_design->get_design()};
261 } else {
262 $c->stash->{rest} = {error => "Could not generate design" };
263 return;
265 $design_layout_view_html = design_layout_view(\%design, \%design_info, $design_type);
266 $design_info_view_html = design_info_view(\%design, \%design_info);
267 my $design_json = encode_json(\%design);
268 $c->stash->{rest} = {
269 success => "1",
270 design_layout_view_html => $design_layout_view_html,
271 design_info_view_html => $design_info_view_html,
272 design_json => $design_json,
276 sub save_experimental_design : Path('/ajax/trial/save_experimental_design') : ActionClass('REST') { }
278 sub save_experimental_design_POST : Args(0) {
279 my ($self, $c) = @_;
280 #my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
281 my $chado_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
282 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema");
283 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema");
284 my $dbh = $c->dbc->dbh;
286 print STDERR "Saving trial... :-)\n";
288 #my $trial_create = new CXGN::Trial::TrialCreate(chado_schema => $schema);
289 if (!$c->user()) {
290 $c->stash->{rest} = {error => "You need to be logged in to add a trial" };
291 return;
293 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) {
294 $c->stash->{rest} = {error => "You have insufficient privileges to add a trial." };
295 return;
297 my $user_id = $c->user()->get_object()->get_sp_person_id();
299 my $user_name = $c->user()->get_object()->get_username();
301 print STDERR "\nUserName: $user_name\n\n";
302 my $error;
304 my $design = _parse_design_from_json($c->req->param('design_json'));
305 #print STDERR Dumper $design;
307 my $greenhouse_num_plants = $c->req->param('greenhouse_num_plants');
308 my $json = JSON->new();
309 if ($greenhouse_num_plants) {
310 $greenhouse_num_plants = $json->decode($greenhouse_num_plants);
312 my $trial_create = CXGN::Trial::TrialCreate
313 ->new({
314 chado_schema => $chado_schema,
315 phenome_schema => $phenome_schema,
316 dbh => $dbh,
317 user_name => $user_name,
318 design => $design,
319 program => $c->req->param('breeding_program_name'),
320 trial_year => $c->req->param('year'),
321 trial_description => $c->req->param('project_description'),
322 trial_location => $c->req->param('trial_location'),
323 trial_name => $c->req->param('project_name'),
324 design_type => $c->req->param('design_type'),
325 greenhouse_num_plants => $greenhouse_num_plants,
328 #$trial_create->set_user($c->user()->id());
329 #$trial_create->set_trial_year($c->req->param('year'));
330 #$trial_create->set_trial_location($c->req->param('trial_location'));
331 #$trial_create->set_trial_description($c->req->param('project_description'));
332 #$trial_create->set_design_type($c->req->param('design_type'));
333 #$trial_create->set_breeding_program_id($c->req->param('breeding_program_name'));
334 #$trial_create->set_design(_parse_design_from_json($c->req->param('design_json')));
335 #$trial_create->set_stock_list(_parse_list_from_json($c->req->param('stock_list')));
336 # if ($c->req->param('control_list')) {
337 # $trial_create->set_control_list(_parse_list_from_json($c->req->param('control_list')));
339 if ($trial_create->trial_name_already_exists()) {
340 $c->stash->{rest} = {error => "Trial name \"".$trial_create->get_trial_name()."\" already exists" };
341 return;
344 try {
345 $trial_create->save_trial();
346 } catch {
347 $c->stash->{rest} = {error => "Error saving trial in the database $_"};
348 print STDERR "ERROR SAVING TRIAL!\n";
349 $error = 1;
351 if ($error) {return;}
352 print STDERR "Trial saved successfully\n";
353 $c->stash->{rest} = {success => "1",};
354 return;
357 sub verify_stock_list : Path('/ajax/trial/verify_stock_list') : ActionClass('REST') { }
359 sub verify_stock_list_POST : Args(0) {
360 my ($self, $c) = @_;
361 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
362 my @stock_names;
363 my $error;
364 my %errors;
365 my $error_alert;
366 if ($c->req->param('stock_list')) {
367 @stock_names = @{_parse_list_from_json($c->req->param('stock_list'))};
368 #my $data = $self->transform_stock_list($c, \@raw_stock_names);
369 #if (exists($data->{missing}) && ref($data->{missing}) && @{$data->{missing}} >0) {
370 # $c->stash->{rest} = { error => "Some stocks were not found. Please edit the list and try again." };
371 # return;
373 # if ($data->{transform} && @{$data->{transform}}>0) {
374 # @stock_names = @{$data->{transform}};
378 if (!@stock_names) {
379 $c->stash->{rest} = {error => "No stock names supplied"};
380 return;
384 foreach my $stock_name (@stock_names) {
386 my $stock;
387 my $number_of_stocks_found;
388 my $stock_lookup = CXGN::Stock::StockLookup->new(schema => $schema);
389 $stock_lookup->set_stock_name($stock_name);
390 $stock = $stock_lookup->get_stock();
391 $number_of_stocks_found = $stock_lookup->get_matching_stock_count();
392 if ($number_of_stocks_found > 1) {
393 $errors{$stock_name} = "Multiple stocks found matching $stock_name\n";
395 if (!$number_of_stocks_found) {
396 $errors{$stock_name} = "No stocks found matching $stock_name\n";
399 if (%errors) {
400 foreach my $key (keys %errors) {
401 $error_alert .= "Stock $key: ".$errors{$key}."\n";
403 $c->stash->{rest} = {error => $error_alert};
404 } else {
405 $c->stash->{rest} = {
406 success => "1",
411 sub _parse_list_from_json {
412 my $list_json = shift;
413 my $json = new JSON;
414 if ($list_json) {
415 my $decoded_list = $json->allow_nonref->utf8->relaxed->escape_slash->loose->allow_singlequote->allow_barekey->decode($list_json);
416 #my $decoded_list = decode_json($list_json);
417 my @array_of_list_items = @{$decoded_list};
418 return \@array_of_list_items;
420 else {
421 return;
425 sub _parse_design_from_json {
426 my $design_json = shift;
427 my $json = new JSON;
428 if ($design_json) {
429 my $decoded_json = $json->allow_nonref->utf8->relaxed->escape_slash->loose->allow_singlequote->allow_barekey->decode($design_json);
430 #my $decoded_json = decode_json($design_json);
431 my %design = %{$decoded_json};
432 return \%design;
434 else {
435 return;
439 ###################################################################################
441 sub upload_trial_file : Path('/ajax/trial/upload_trial_file') : ActionClass('REST') { }
443 sub upload_trial_file_POST : Args(0) {
444 my ($self, $c) = @_;
446 print STDERR "Check 1: ".localtime();
448 my $chado_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
449 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema");
450 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema");
451 my $dbh = $c->dbc->dbh;
452 my $program = $c->req->param('trial_upload_breeding_program');
453 my $trial_location = $c->req->param('trial_upload_location');
454 my $trial_name = $c->req->param('trial_upload_name');
455 my $trial_year = $c->req->param('trial_upload_year');
456 my $trial_description = $c->req->param('trial_upload_description');
457 my $trial_design_method = $c->req->param('trial_upload_design_method');
458 my $upload = $c->req->upload('trial_uploaded_file');
459 my $uploader = CXGN::UploadFile->new();
460 my $parser;
461 my $parsed_data;
462 my $upload_original_name = $upload->filename();
463 my $upload_tempfile = $upload->tempname;
464 my $subdirectory = "trial_upload";
465 my $archived_filename_with_path;
466 my $md5;
467 my $validate_file;
468 my $parsed_file;
469 my $parse_errors;
470 my %parsed_data;
471 my %upload_metadata;
472 my $time = DateTime->now();
473 my $timestamp = $time->ymd()."_".$time->hms();
474 my $user_id;
475 my $user_name;
476 my $error;
478 print STDERR "Check 2: ".localtime();
480 if ($upload_original_name =~ /\s/ || $upload_original_name =~ /\// || $upload_original_name =~ /\\/ ) {
481 print STDERR "File name must not have spaces or slashes.\n";
482 $c->stash->{rest} = {error => "Uploaded file name must not contain spaces or slashes." };
483 return;
486 if (!$c->user()) {
487 print STDERR "User not logged in... not adding a crosses.\n";
488 $c->stash->{rest} = {error => "You need to be logged in to add a cross." };
489 return;
491 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) {
492 $c->stash->{rest} = {error => "You have insufficient privileges to add a trial." };
493 return;
496 $user_id = $c->user()->get_object()->get_sp_person_id();
498 $user_name = $c->user()->get_object()->get_username();
500 ## Store uploaded temporary file in archive
501 $archived_filename_with_path = $uploader->archive($c, $subdirectory, $upload_tempfile, $upload_original_name, $timestamp);
502 $md5 = $uploader->get_md5($archived_filename_with_path);
503 if (!$archived_filename_with_path) {
504 $c->stash->{rest} = {error => "Could not save file $upload_original_name in archive",};
505 return;
507 unlink $upload_tempfile;
509 print STDERR "Check 3: ".localtime();
511 $upload_metadata{'archived_file'} = $archived_filename_with_path;
512 $upload_metadata{'archived_file_type'}="trial upload file";
513 $upload_metadata{'user_id'}=$user_id;
514 $upload_metadata{'date'}="$timestamp";
516 #parse uploaded file with appropriate plugin
517 $parser = CXGN::Trial::ParseUpload->new(chado_schema => $chado_schema, filename => $archived_filename_with_path);
518 $parser->load_plugin('TrialExcelFormat');
519 $parsed_data = $parser->parse();
521 if (!$parsed_data) {
522 my $return_error = '';
524 if (! $parser->has_parse_errors() ){
525 $return_error = "Could not get parsing errors";
526 $c->stash->{rest} = {error_string => $return_error,};
529 else {
530 $parse_errors = $parser->get_parse_errors();
531 #print STDERR Dumper $parse_errors;
533 foreach my $error_string (@{$parse_errors->{'error_messages'}}){
534 $return_error=$return_error.$error_string."<br>";
538 $c->stash->{rest} = {error_string => $return_error, missing_accessions => $parse_errors->{'missing_accessions'}};
539 return;
542 print STDERR "Check 4: ".localtime();
544 #print STDERR Dumper $parsed_data;
546 my $trial_create = CXGN::Trial::TrialCreate
547 ->new({
548 chado_schema => $chado_schema,
549 phenome_schema => $phenome_schema,
550 dbh => $dbh,
551 trial_year => $trial_year,
552 trial_description => $trial_description,
553 trial_location => $trial_location,
554 trial_name => $trial_name,
555 user_name => $user_name, #not implemented
556 design_type => $trial_design_method,
557 design => $parsed_data,
558 program => $program,
559 upload_trial_file => $upload,
562 try {
563 $trial_create->save_trial();
564 } catch {
565 $c->stash->{rest} = {error => "Error saving trial in the database $_"};
566 $error = 1;
569 print STDERR "Check 5: ".localtime();
571 if ($error) {return;}
572 $c->stash->{rest} = {success => "1",};
573 return;
580 ###################################################################################
581 ##remove this soon. using above instead
582 sub upload_trial_layout : Path('/trial/upload_trial_layout') : ActionClass('REST') { }
584 sub upload_trial_layout_POST : Args(0) {
585 my ($self, $c) = @_;
586 my @contents;
587 my $error = 0;
588 my $upload = $c->req->upload('trial_upload_file');
589 my $header_line;
590 my @header_contents;
591 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
592 if (!$c->user()) { #user must be logged in
593 $c->stash->{rest} = {error => "You need to be logged in to upload a file." };
594 return;
596 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) { #user must have privileges to add a trial
597 $c->stash->{rest} = {error => "You have insufficient privileges to upload a file." };
598 return;
600 if (!$upload) { #upload file required
601 $c->stash->{rest} = {error => "File upload failed: no file name received"};
602 return;
604 try { #get file contents
605 @contents = split /\n/, $upload->slurp;
606 } catch {
607 $c->stash->{rest} = {error => "File upload failed: $_"};
608 $error = 1;
610 if ($error) {return;}
611 if (@contents < 2) { #upload file must contain at least one line of data plus a header
612 $c->stash->{rest} = {error => "File upload failed: contains less than two lines"};
613 return;
615 $header_line = shift(@contents);
616 @header_contents = split /\t/, $header_line;
617 try { #verify header contents
618 _verify_trial_layout_header(\@header_contents);
619 } catch {
620 $c->stash->{rest} = {error => "File upload failed: $_"};
621 $error = 1;
623 if ($error) {return;}
625 #verify location
626 if (! $schema->resultset("NaturalDiversity::NdGeolocation")->find({description=>$c->req->param('add_project_location'),})){
627 $c->stash->{rest} = {error => "File upload failed: location not found"};
628 return;
631 try { #verify contents of file
632 _verify_trial_layout_contents($self, $c, \@contents);
633 } catch {
634 my %error_hash = %{$_};
635 #my $error_string = Dumper(%error_hash);
636 my $error_string = _formatted_string_from_error_hash(\%error_hash);
637 $c->stash->{rest} = {error => "File upload failed: missing or invalid content (see details that follow..)", error_string => "$error_string"};
638 $error = 1;
640 if ($error) {return;}
642 try { #add file contents to the database
643 _add_trial_layout_to_database($self,$c,\@contents);
644 } catch {
645 $c->stash->{rest} = {error => "File upload failed: $_"};
648 if ($error) {
649 return;
650 } else {
651 $c->stash->{rest} = {success => "1"};
655 sub _add_trial_layout_to_database {
656 my $self = shift;
657 my $c = shift;
658 my $contents_ref = shift;
659 my @contents = @{$contents_ref};
660 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
661 my $year = $c->req->param('add_project_year');
662 my $location = $c->req->param('add_project_location');
663 my $project_name = $c->req->param('add_project_name');
664 my $project_description = $c->req->param('add_project_description');
665 my $plot_cvterm = SGN::Model::Cvterm->get_cvterm_row($schema, 'plot', 'stock_type');
666 my $geolocation = $schema->resultset("NaturalDiversity::NdGeolocation")
667 ->find_or_create({
668 description => $location, #add this as an option
670 my $organism = $schema->resultset("Organism::Organism")
671 ->find_or_create({
672 genus => 'Manihot',
673 species => 'Manihot esculenta',
676 #this is wrong. Does not seem to be used in the database !!
677 my $plot_exp_cvterm = SGN::Model::Cvterm->get_cvterm_row($schema, 'plot_experiment', 'experiment_type');
680 #create project
681 my $project = $schema->resultset('Project::Project')
682 ->find_or_create({
683 name => $project_name,
684 description => $location,
688 my $projectprop_year = $project->create_projectprops( { 'project year' => $year,}, {autocreate=>1});
689 my $organism_id = $organism->organism_id();
691 foreach my $content_line (@contents) {
692 my @line_contents = split /\t/, $content_line;
693 my $plot_name = $line_contents[0];
694 my $block_number = $line_contents[1];
695 my $rep_number = $line_contents[2];
696 my $stock_name = $line_contents[3];
697 my $stock;
698 my $stock_rs = $schema->resultset("Stock::Stock")
699 ->search({
700 -or => [
701 'lower(me.uniquename)' => { like => lc($stock_name) },
702 -and => [
703 'lower(type.name)' => { like => '%synonym%' },
704 'lower(stockprops.value)' => { like => lc($stock_name) },
709 join => { 'stockprops' => 'type'} ,
710 distinct => 1
713 if ($stock_rs->count >1 ) {
714 die ("multiple stocks found matching $stock_name");
715 } elsif ($stock_rs->count == 1) {
716 $stock = $stock_rs->first;
717 } else {
718 die ("no stocks found matching $stock_name");
720 my $unique_plot_name =
721 $project_name."_".$stock_name."_plot_".$plot_name."_block_".$block_number."_rep_".$rep_number."_".$year."_".$location;
722 my $plot = $schema->resultset("Stock::Stock")
723 ->find_or_create({
724 organism_id => $stock->organism_id(),
725 name => $unique_plot_name,
726 uniquename => $unique_plot_name,
727 type_id => $plot_cvterm->cvterm_id,
729 my $experiment = $schema->resultset('NaturalDiversity::NdExperiment')
730 ->create({
731 nd_geolocation_id => $geolocation->nd_geolocation_id(),
732 type_id => $plot_exp_cvterm->cvterm_id(),
734 #link to the project
735 $experiment
736 ->find_or_create_related('nd_experiment_projects',{
737 project_id => $project->project_id()
739 #link the experiment to the stock
740 $experiment
741 ->find_or_create_related('nd_experiment_stocks' ,{
742 stock_id => $plot->stock_id(),
743 type_id => $plot_exp_cvterm->cvterm_id(),
748 sub _verify_trial_layout_header {
749 my $header_content_ref = shift;
750 my @header_contents = @{$header_content_ref};
751 if ($header_contents[0] ne 'plot_name' ||
752 $header_contents[1] ne 'block_number' ||
753 $header_contents[2] ne 'rep_number' ||
754 $header_contents[3] ne 'stock_name') {
755 die ("Wrong column names in header\n");
757 if (@header_contents != 4) {
758 die ("Wrong number of columns in header\n");
760 return;
763 sub _verify_trial_layout_contents {
764 my $self = shift;
765 my $c = shift;
766 my $contents_ref = shift;
767 my @contents = @{$contents_ref};
768 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado');
769 my $year = $c->req->param('add_project_year');
770 my $location = $c->req->param('add_project_location');
771 my $project_name = $c->req->param('add_project_name');
772 my $line_number = 1;
773 my %error_hash;
774 my %plot_name_errors;
775 my %block_number_errors;
776 my %rep_number_errors;
777 my %stock_name_errors;
778 my %column_number_errors;
779 foreach my $content_line (@contents) {
780 my @line_contents = split /\t/, $content_line;
781 if (@line_contents != 4) {
782 my $column_count = scalar(@line_contents);
783 $column_number_errors{$line_number} = "Line $line_number: wrong number of columns, expected 4, found $column_count";
784 $line_number++;
785 next;
787 my $plot_name = $line_contents[0];
788 my $block_number = $line_contents[1];
789 my $rep_number = $line_contents[2];
790 my $stock_name = $line_contents[3];
791 if (!$stock_name) {
792 $stock_name_errors{$line_number} = "Line $line_number: stock name is missing";
793 } else {
794 #make sure stock name exists and returns a unique result
795 my $stock_rs = $schema->resultset("Stock::Stock")
796 ->search({
797 -or => [
798 'lower(me.uniquename)' => { like => lc($stock_name) },
799 -and => [
800 'lower(type.name)' => { like => '%synonym%' },
801 'lower(stockprops.value)' => { like => lc($stock_name) },
806 join => { 'stockprops' => 'type'} ,
807 distinct => 1
810 if ($stock_rs->count >1 ) {
811 my $error_string = "Line $line_number: multiple accessions found for stock name $stock_name (";
812 while ( my $st = $stock_rs->next) {
813 my $error_string .= $st->uniquename.",";
815 $stock_name_errors{$line_number} = $error_string;
816 } elsif ($stock_rs->count == 1) {
817 } else {
818 $stock_name_errors{$line_number} = "Line $line_number: stock name $stock_name not found";
822 if (!$plot_name) {
823 $plot_name_errors{$line_number} = "Line $line_number: plot name is missing";
824 } else {
825 my $unique_plot_name = $project_name."_".$stock_name."_plot_".$plot_name."_block_".$block_number."_rep_".$rep_number."_".$year."_".$location;
826 if ($schema->resultset("Stock::Stock")->find({uniquename=>$unique_plot_name,})) {
827 $plot_name_errors{$line_number} = "Line $line_number: plot name $unique_plot_name is not unique";
831 #check for valid block number
832 if (!$block_number) {
833 $block_number_errors{$line_number} = "Line $line_number: block number is missing";
834 } else {
835 if (!($block_number =~ /^\d+?$/)) {
836 $block_number_errors{$line_number} = "Line $line_number: block number $block_number is not an integer";
837 } elsif ($block_number < 1 || $block_number > 1000000) {
838 $block_number_errors{$line_number} = "Line $line_number: block number $block_number is out of range";
842 #check for valid rep number
843 if (!$rep_number) {
844 $rep_number_errors{$line_number} = "Line $line_number: rep number is missing";
845 } else {
846 if (!($rep_number =~ /^\d+?$/)) {
847 $rep_number_errors{$line_number} = "Line $line_number: rep number $rep_number is not an integer";
848 } elsif ($rep_number < 1 || $rep_number > 1000000) {
849 $rep_number_errors{$line_number} = "Line $line_number: rep number $block_number is out of range";
852 $line_number++;
855 if (%plot_name_errors) {$error_hash{'plot_name_errors'}=\%plot_name_errors;}
856 if (%block_number_errors) {$error_hash{'block_number_errors'}=\%block_number_errors;}
857 if (%rep_number_errors) {$error_hash{'rep_number_errors'}=\%rep_number_errors;}
858 if (%stock_name_errors) {$error_hash{'stock_name_errors'}=\%stock_name_errors;}
859 if (%column_number_errors) {$error_hash{'column_number_errors'}=\%column_number_errors;}
860 if (%error_hash) {
861 die (\%error_hash);
863 return;
866 sub _formatted_string_from_error_hash {
867 my $error_hash_ref = shift;
868 my %error_hash = %{$error_hash_ref};
869 my $error_string ;
870 if ($error_hash{column_number_errors}) {
871 $error_string .= "<b>Column number errors</b><br><br>"._formatted_string_from_error_hash_by_type(\%{$error_hash{column_number_errors}})."<br><br>";
873 if ($error_hash{stock_name_errors}) {
874 $error_string .= "<b>Stock name errors</b><br><br>"._formatted_string_from_error_hash_by_type(\%{$error_hash{stock_name_errors}})."<br><br>";
876 if ($error_hash{'plot_name_errors'}) {
877 $error_string .= "<b>Plot name errors</b><br><br>"._formatted_string_from_error_hash_by_type(\%{$error_hash{'plot_name_errors'}})."<br><br>";
879 if ($error_hash{'block_number_errors'}) {
880 $error_string .= "<b>Block number errors</b><br><br>"._formatted_string_from_error_hash_by_type(\%{$error_hash{'block_number_errors'}})."<br><br>";
882 if ($error_hash{'rep_number_errors'}) {
883 $error_string .= "<b>Rep number errors</b><br><br>"._formatted_string_from_error_hash_by_type(\%{$error_hash{'rep_number_errors'}})."<br><br>";
885 return $error_string;
888 sub _formatted_string_from_error_hash_by_type {
889 my $error_hash_ref = shift;
890 my %error_hash = %{$error_hash_ref};
891 my $error_string;
892 foreach my $key (sort { $a <=> $b} keys %error_hash) {
893 $error_string .= $error_hash{$key} . "<br>";
895 return $error_string;
899 ### The following was moved to TrialMetadata.
900 # sub trial : Chained('/') PathPart('ajax/breeders/trial') CaptureArgs(1) {
901 # my $self = shift;
902 # my $c = shift;
903 # my $trial_id = shift;
905 # print STDERR "TRIAL ID: $trial_id\n";
906 # $c->stash->{trial_id} = $trial_id;
907 # $c->stash->{trial} = CXGN::Trial->new( { bcs_schema => $c->dbic_schema("Bio::Chado::Schema"), trial_id => $trial_id });
909 # if (!$c->stash->{trial}) {
910 # $c->stash->{rest} = { error => "The specified trial with id $trial_id does not exist" };
911 # return;
917 # =head2 delete_trial_by_file
919 # Usage:
920 # Desc:
921 # Ret:
922 # Args:
923 # Side Effects:
924 # Example:
926 # =cut
928 # sub delete_trial_by_file : Path('/breeders/trial/delete/file') Args(1) {
929 # my $self = shift;
930 # my $c = shift;
932 # my $file_id = shift;
934 # if (!$c->user()) {
935 # $c->stash->{rest} = { error => 'You must be logged in to delete a trial' };
936 # return;
939 # if (! ($c->user->check_roles('curator') || $c->user->check_roles('submitter'))) {
940 # $c->stash->{rest} = { error => 'You do not have sufficient privileges to delete a trial.' };
943 # my $del = CXGN::BreedersToolbox::Delete->new(
944 # bcs_schema => $c->dbic_schema("Bio::Chado::Schema"),
945 # metadata_schema => $c->dbic_schema("CXGN::Metadata::Schema"),
946 # phenome_schema => $c->dbic_schema("CXGN::Phenome::Schema"),
947 # );
949 # if ($del->delete_experiments_by_file($c->user->get_object()->get_sp_person_id(), $file_id)) {
950 # $c->stash->{rest} = { success => 1 };
952 # else {
953 # $c->stash->{rest} = { error => "The trial information could not be removed from the database." };
958 # =head2 delete_trial_by_trial_id
960 # Usage:
961 # Desc: Deletes plots associated with a phenotyping experiment
962 # Ret:
963 # Args:
964 # Side Effects:
965 # Example:
967 # =cut
969 # sub delete_trial_by_trial_id : Path('/breeders/trial/delete/id') Args(1) {
970 # my $self = shift;
971 # my $c = shift;
973 # my $trial_id = shift;
975 # print STDERR "DELETING trial $trial_id\n";
977 # if (!$c->user()) {
978 # $c->stash->{rest} = { error => 'You must be logged in to delete a trial' };
979 # return;
982 # my $user_id = $c->user->get_object()->get_sp_person_id();
984 # my $schema = $c->dbic_schema("Bio::Chado::Schema");
986 # my $breeding_program_rs = $schema->resultset("Cv::Cvterm")->search( { name => "breeding_program" });
988 # my $breeding_program_id = $breeding_program_rs->first()->cvterm_id();
990 # my $breeding_program_name = $breeding_program_rs->first()->name();
992 # my $trial_organization_id = $schema->resultset("Project::Projectprop")->search(
994 # project_id => $trial_id,
995 # type_id=>$breeding_program_id
996 # });
998 # if (! ($c->user->check_roles('curator') || ( $c->user->check_roles('submitter') && $c->roles($breeding_program_name) ))) {
999 # $c->stash->{rest} = { error => 'You do not have sufficient privileges to delete a trial.' };
1002 # # my $del = CXGN::BreedersToolbox::Delete->new(
1003 # # bcs_schema => $c->dbic_schema("Bio::Chado::Schema"),
1004 # # metadata_schema => $c->dbic_schema("CXGN::Metadata::Schema"),
1005 # # phenome_schema => $c->dbic_schema("CXGN::Phenome::Schema"),
1006 # # );
1008 # my $t = CXGN::Trial->new( { trial_id=> $trial_id, bcs_schema => $c->dbic_schema("Bio::Chado::Schema") });
1010 # my $hash = $t->delete_experiments($user_id, $trial_id);
1012 # $c->stash->{rest} = $hash;
1016 # =head2 delete_phenotype_data_by_trial_id
1018 # Usage:
1019 # Desc:
1020 # Ret:
1021 # Args:
1022 # Side Effects:
1023 # Example:
1025 # =cut
1027 # sub delete_phenotype_data_by_trial_id : Path('/breeders/trial/phenotype/delete/id') Args(1) {
1028 # my $self = shift;
1029 # my $c = shift;
1031 # my $trial_id = shift;
1033 # print STDERR "DELETING phenotypes of trial $trial_id\n";
1035 # if (!$c->user()) {
1036 # $c->stash->{rest} = { error => 'You must be logged in to delete a trial' };
1037 # return;
1040 # my $user_id = $c->user->get_object()->get_sp_person_id();
1042 # my $schema = $c->dbic_schema("Bio::Chado::Schema");
1044 # my $breeding_program_rs = $schema->resultset("Cv::Cvterm")->search( { name => "breeding_program" });
1046 # my $breeding_program_id = $breeding_program_rs->first()->cvterm_id();
1048 # my $breeding_program_name = $breeding_program_rs->first()->name();
1050 # my $trial_organization_id = $schema->resultset("Project::Projectprop")->search(
1052 # project_id => $trial_id,
1053 # type_id=>$breeding_program_id
1054 # });
1056 # if (! ($c->user->check_roles('curator') || ( $c->user->check_roles('submitter') && $c->roles($breeding_program_name) ))) {
1057 # $c->stash->{rest} = { error => 'You do not have sufficient privileges to delete a trial.' };
1060 # my $t = CXGN::Trial->new( { trial_id => $trial_id, bcs_schema => $c->dbic_schema("Bio::Chado::Schema") });
1062 # my $error = $t->delete_metadata($c->dbic_schema("CXGN::Metadata::Schema"), $c->dbic_schema("CXGN::Phenome::Schema"));
1064 # print STDERR "ERROR DELETING METADATA: $error\n";
1065 # my $error = $t->delete_phenotype_data($trial_id);
1067 # print STDERR "ERROR DELETING PHENOTYPES: $error\n";
1068 # if ($error) {
1069 # $c->stash->{rest} = { error => $error };
1071 # else {
1072 # $c->stash->{rest} = { success => "1" };
1076 # =head2 delete_trial_layout_by_trial_id
1078 # Usage:
1079 # Desc:
1080 # Ret:
1081 # Args:
1082 # Side Effects:
1083 # Example:
1085 # =cut
1087 # sub delete_trial_layout_by_trial_id : Path('/breeders/trial/layout/delete/id') Args(1) {
1088 # my $self = shift;
1089 # my $c = shift;
1091 # my $trial_id = shift;
1093 # print STDERR "DELETING trial layout $trial_id\n";
1095 # if (!$c->user()) {
1096 # $c->stash->{rest} = { error => 'You must be logged in to delete a trial layout' };
1097 # return;
1100 # my $user_id = $c->user->get_object()->get_sp_person_id();
1102 # my $schema = $c->dbic_schema("Bio::Chado::Schema");
1104 # my $breeding_program_rs = $schema->resultset("Cv::Cvterm")->search( { name => "breeding_program" });
1106 # my $breeding_program_id = $breeding_program_rs->first()->cvterm_id();
1108 # my $breeding_program_name = $breeding_program_rs->first()->name();
1110 # my $trial_organization_id = $schema->resultset("Project::Projectprop")->search(
1112 # project_id => $trial_id,
1113 # type_id=>$breeding_program_id
1114 # });
1116 # if (! ($c->user->check_roles('curator') || ( $c->user->check_roles('submitter') && $c->roles($breeding_program_name) ))) {
1117 # $c->stash->{rest} = { error => 'You do not have sufficient privileges to delete a trial.' };
1120 # #my $del = CXGN::BreedersToolbox::Delete->new(
1121 # # bcs_schema => $c->dbic_schema("Bio::Chado::Schema"),
1122 # # metadata_schema => $c->dbic_schema("CXGN::Metadata::Schema"),
1123 # # phenome_schema => $c->dbic_schema("CXGN::Phenome::Schema"),
1124 # # );
1126 # my $t = CXGN::Trial->new( { bcs_schema => $c->dbic_schema("Bio::Chado::Schema"), trial_id => $trial_id });
1127 # #my $error = $del->delete_field_layout_by_trial($trial_id);
1129 # my $error = $t->delete_field_layout();
1130 # if ($error) {
1131 # $c->stash->{rest} = { error => $error };
1133 # $c->stash->{rest} = { success => 1 };
1139 # sub trial_description : Local() ActionClass('REST');
1141 # sub trial_description_GET : Chained('trial') PathPart('description') Args(0) {
1142 # my $self = shift;
1143 # my $c = shift;
1145 # my $trial = $c->stash->{trial};
1147 # print STDERR "TRIAL: ".$trial->get_description()."\n";
1149 # $c->stash->{rest} = { description => $trial->get_description() };
1153 # sub trial_description_POST : Chained('trial') PathPart('description') Args(1) {
1154 # my $self = shift;
1155 # my $c = shift;
1156 # my $description = shift;
1158 # if (!($c->user()->check_roles('curator') || $c->user()->check_roles('submitter'))) {
1159 # $c->stash->{rest} = { error => 'You do not have the required privileges to edit the trial type of this trial.' };
1160 # return;
1163 # my $trial_id = $c->stash->{trial_id};
1164 # my $trial = $c->stash->{trial};
1166 # my $p = CXGN::BreedersToolbox::Projects->new( { schema => $c->dbic_schema("Bio::Chado::Schema") });
1168 # my $breeding_program = $p->get_breeding_programs_by_trial($trial_id);
1170 # if (! ($c->user() && ($c->user->check_roles("curator") || $c->user->check_roles($breeding_program)))) {
1171 # $c->stash->{rest} = { error => "You need to be logged in with sufficient privileges to change the description of a trial." };
1172 # return;
1175 # $trial->set_description($description);
1177 # $c->stash->{rest} = { success => 1 };
1180 # # sub get_trial_type :Path('/ajax/breeders/trial/type') Args(1) {
1181 # # my $self = shift;
1182 # # my $c = shift;
1183 # # my $trial_id = shift;
1185 # # my $t = CXGN::Trial->new( { bcs_schema => $c->dbic_schema("Bio::Chado::Schema"), trial_id => $trial_id } );
1187 # # $c->stash->{rest} = { type => $t->get_project_type() };
1189 # # }
1192 # sub trial_location : Local() ActionClass('REST');
1194 # sub trial_location_GET : Chained('trial') PathPart('location') Args(0) {
1195 # my $self = shift;
1196 # my $c = shift;
1198 # my $t = $c->stash->{trial};
1200 # $c->stash->{rest} = { location => [ $t->get_location()->[0], $t->get_location()->[1] ] };
1204 # sub trial_location_POST : Chained('trial') PathPart('location') Args(1) {
1205 # my $self = shift;
1206 # my $c = shift;
1207 # my $location_id = shift;
1209 # if (!($c->user()->check_roles('curator') || $c->user()->check_roles('submitter'))) {
1210 # $c->stash->{rest} = { error => 'You do not have the required privileges to edit the trial type of this trial.' };
1211 # return;
1214 # print STDERR "trial location POST!\n";
1216 # #my $location_id = $c->req->param("location_id");
1218 # my $t = $c->stash->{trial};
1219 # my $trial_id = $c->stash->{trial_id};
1221 # # remove old location
1223 # $t->remove_location($t->get_location()->[0]);
1225 # # add new one
1227 # $t->set_location($location_id);
1229 # $c->stash->{rest} = { message => "Successfully stored location for trial $trial_id",
1230 # trial_id => $trial_id };
1234 # sub trial_year : Local() ActionClass('REST');
1236 # sub trial_year_GET : Chained('trial') PathPart('year') Args(0) {
1237 # my $self = shift;
1238 # my $c = shift;
1240 # my $t = $c->stash->{trial};
1242 # $c->stash->{rest} = { year => $t->get_year() };
1246 # sub trial_year_POST : Chained('trial') PathPart('year') Args(1) {
1247 # my $self = shift;
1248 # my $c = shift;
1249 # my $year = shift;
1251 # if (!($c->user()->check_roles('curator') || $c->user()->check_roles('submitter'))) {
1252 # $c->stash->{rest} = { error => 'You do not have the required privileges to edit the trial type of this trial.' };
1253 # return;
1256 # my $t = $c->stash->{trial};
1258 # $t->set_year($year);
1260 # $c->stash->{rest} = { message => "Year set successfully" };
1263 # sub trial_type : Local() ActionClass('REST');
1265 # sub trial_type_GET : Chained('trial') PathPart('type') Args(0) {
1266 # my $self = shift;
1267 # my $c = shift;
1269 # my $t = $c->stash->{trial};
1271 # my $type = $t->get_project_type();
1272 # $c->stash->{rest} = { type => $type };
1275 # sub trial_type_POST : Chained('trial') PathPart('type') Args(1) {
1276 # my $self = shift;
1277 # my $c = shift;
1278 # my $type = shift;
1280 # if (!($c->user()->check_roles('curator') || $c->user()->check_roles('submitter'))) {
1281 # $c->stash->{rest} = { error => 'You do not have the required privileges to edit the trial type of this trial.' };
1282 # return;
1285 # my $t = $c->stash->{trial};
1286 # my $trial_id = $c->stash->{trial_id};
1288 # # set the new trial type
1290 # $t->set_project_type($type);
1292 # $c->stash->{rest} = { success => 1 };