clean
[sgn.git] / lib / SGN / Controller / AJAX / BreedersToolbox.pm
blobf184fa099f3e8524524d87cb6a34dc1e79bba1a4
2 package SGN::Controller::AJAX::BreedersToolbox;
4 use Moose;
6 use URI::FromHash 'uri';
7 use Data::Dumper;
8 use File::Slurp "read_file";
10 use CXGN::List;
11 use CXGN::BreedersToolbox::Projects;
12 use CXGN::BreedersToolbox::Delete;
13 use CXGN::Trial::TrialDesign;
14 use CXGN::Trial::TrialCreate;
15 use CXGN::Stock::StockLookup;
16 use Try::Tiny;
18 BEGIN { extends 'Catalyst::Controller::REST' }
20 __PACKAGE__->config(
21 default => 'application/json',
22 stash_key => 'rest',
23 map => { 'application/json' => 'JSON', 'text/html' => 'JSON' },
26 sub insert_new_project : Path("/ajax/breeders/project/insert") Args(0) {
27 my $self = shift;
28 my $c = shift;
30 if (! $c->user()) {
31 $c->stash->{rest} = { error => "You must be logged in to add projects." } ;
32 return;
35 my $params = $c->req->parameters();
37 my $schema = $c->dbic_schema('Bio::Chado::Schema');
39 my $exists = $schema->resultset('Project::Project')->search(
40 { name => $params->{project_name} }
43 if ($exists > 0) {
44 $c->stash->{rest} = { error => "This trial name is already used." };
45 return;
49 my $project = $schema->resultset('Project::Project')->find_or_create(
51 name => $params->{project_name},
52 description => $params->{project_description},
56 my $projectprop_year = $project->create_projectprops( { 'project year' => $params->{year},}, {autocreate=>1}); #cv_name => 'project_property' } );
60 $c->stash->{rest} = { error => '' };
63 sub get_all_locations :Path("/ajax/breeders/location/all") Args(0) {
64 my $self = shift;
65 my $c = shift;
67 my $bp = CXGN::BreedersToolbox::Projects->new( { schema => $c->dbic_schema("Bio::Chado::Schema") });
69 my $all_locations = $bp->get_all_locations();
71 $c->stash->{rest} = { locations => $all_locations };
75 sub insert_new_location :Path("/ajax/breeders/location/insert") Args(0) {
76 my $self = shift;
77 my $c = shift;
79 my $params = $c->request->parameters();
81 my $description = $params->{description};
82 my $longitude = $params->{longitude};
83 my $latitude = $params->{latitude};
84 my $altitude = $params->{altitude};
86 if (! $c->user()) { # redirect
87 $c->stash->{rest} = { error => 'You must be logged in to add a location.' };
88 return;
91 if (! $c->user->check_roles("submitter") && !$c->user->check_roles("curator")) {
92 $c->stash->{rest} = { error => 'You do not have the necessary privileges to add locations.' };
93 return;
95 my $schema = $c->dbic_schema('Bio::Chado::Schema');
97 my $exists = $schema->resultset('NaturalDiversity::NdGeolocation')->search( { description => $description } )->count();
99 if ($exists > 0) {
100 $c->stash->{rest} = { error => "The location - $description - already exists. Please choose another name." };
101 return;
104 if ( ($longitude && $longitude !~ /^-?[0-9.]+$/) || ($latitude && $latitude !~ /^-?[0-9.]+$/) || ($altitude && $altitude !~ /^[0-9.]+$/) ) {
105 $c->stash->{rest} = { error => "Longitude, latitude and altitude must be numbers." };
106 return;
109 my $new_row;
110 $new_row = $schema->resultset('NaturalDiversity::NdGeolocation')
111 ->new({
112 description => $description,
114 if ($longitude) {
115 $new_row->longitude($longitude);
117 if ($latitude) {
118 $new_row->latitude($latitude);
120 if ($altitude) {
121 $new_row->altitude($altitude);
123 $new_row->insert();
124 $c->stash->{rest} = { success => 1, error => '' };
127 sub delete_location :Path('/ajax/breeders/location/delete') Args(1) {
128 my $self = shift;
129 my $c = shift;
130 my $location_id = shift;
132 if (!$c->user) { # require login
133 $c->stash->{rest} = { error => "You need to be logged in to delete a location." };
134 return;
136 # require curator or submitter roles
137 if (! ($c->user->check_roles('curator') || $c->user->check_roles('submitter'))) {
138 $c->stash->{rest} = { error => "You don't have the privileges to delete a location." };
139 return;
141 my $del = CXGN::BreedersToolbox::Delete->new( { bcs_schema => $c->dbic_schema("Bio::Chado::Schema") } );
142 if ($del->can_delete_location($location_id)) {
143 my $success = $del->delete_location($location_id);
145 if ($success) {
146 $c->stash->{rest} = { success => 1 };
148 else {
149 $c->stash->{rest} = { error => "Could not delete location $location_id" };
152 else {
153 $c->stash->{rest} = { error => "This location cannot be deleted because it has associated data." }
158 sub get_breeding_programs : Path('/ajax/breeders/all_programs') Args(0) {
159 my $self = shift;
160 my $c = shift;
162 my $po = CXGN::BreedersToolbox::Projects->new( { schema => $c->dbic_schema("Bio::Chado::Schema") });
164 my $breeding_programs = $po->get_breeding_programs();
166 $c->stash->{rest} = $breeding_programs;
169 sub new_breeding_program :Path('/breeders/program/new') Args(0) {
170 my $self = shift;
171 my $c = shift;
172 my $name = $c->req->param("name");
173 my $desc = $c->req->param("desc");
175 if (!($c->user() || $c->user()->check_roles('submitter'))) {
176 $c->stash->{rest} = { error => 'You need to be logged in and have sufficient privileges to add a breeding program.' };
180 my $p = CXGN::BreedersToolbox::Projects->new( { schema => $c->dbic_schema("Bio::Chado::Schema") });
182 my $error = $p->new_breeding_program($name, $desc);
184 if ($error) {
185 $c->stash->{rest} = { error => $error };
187 else {
188 $c->stash->{rest} = {};
193 sub delete_breeding_program :Path('/breeders/program/delete') Args(1) {
194 my $self = shift;
195 my $c = shift;
196 my $program_id = shift;
198 if ($c->user && ($c->user->check_roles("curator"))) {
199 my $p = CXGN::BreedersToolbox::Projects->new( { schema => $c->dbic_schema("Bio::Chado::Schema") });
200 $p->delete_breeding_program($program_id);
201 $c->stash->{rest} = [ 1 ];
203 else {
204 $c->stash->{rest} = { error => "You don't have sufficient privileges to delete breeding programs." };
209 sub get_breeding_programs_by_trial :Path('/breeders/programs_by_trial/') Args(1) {
210 my $self = shift;
211 my $c = shift;
212 my $trial_id = shift;
214 my $p = CXGN::BreedersToolbox::Projects->new( { schema => $c->dbic_schema("Bio::Chado::Schema") } );
216 my $projects = $p->get_breeding_programs_by_trial($trial_id);
218 $c->stash->{rest} = { projects => $projects };
222 sub add_data_agreement :Path('/breeders/trial/add/data_agreement') Args(0) {
223 my $self = shift;
224 my $c = shift;
226 my $project_id = $c->req->param('project_id');
227 my $data_agreement = $c->req->param('text');
229 if (!$c->user()) {
230 $c->stash->{rest} = { error => 'You need to be logged in to add a data agreement' };
231 return;
234 if (!($c->user()->check_roles('curator') || $c->user()->check_roles('submitter'))) {
235 $c->stash->{rest} = { error => 'You do not have the required privileges to add a data agreement to this trial.' };
236 return;
239 my $schema = $c->dbic_schema('Bio::Chado::Schema');
241 my $data_agreement_cvterm_id_rs = $schema->resultset('Cv::Cvterm')->search( { name => 'data_agreement' });
243 my $type_id;
244 if ($data_agreement_cvterm_id_rs->count>0) {
245 $type_id = $data_agreement_cvterm_id_rs->first()->cvterm_id();
248 eval {
249 my $project_rs = $schema->resultset('Project::Project')->search(
250 { project_id => $project_id }
253 if ($project_rs->count() == 0) {
254 $c->stash->{rest} = { error => "No such project $project_id", };
255 return;
258 my $project = $project_rs->first();
260 my $projectprop_rs = $schema->resultset("Project::Projectprop")->search( { 'project_id' => $project_id, 'type_id'=>$type_id });
262 my $projectprop;
263 if ($projectprop_rs->count() > 0) {
264 $projectprop = $projectprop_rs->first();
265 $projectprop->value($data_agreement);
266 $projectprop->update();
267 $c->stash->{rest} = { message => 'Updated data agreement.' };
269 else {
270 $projectprop = $project->create_projectprops( { 'data_agreement' => $data_agreement,}, {autocreate=>1});
271 $c->stash->{rest} = { message => 'Inserted new data agreement.'};
274 if ($@) {
275 $c->stash->{rest} = { error => $@ };
276 return;
280 sub get_data_agreement :Path('/breeders/trial/data_agreement/get') :Args(0) {
281 my $self = shift;
282 my $c = shift;
284 my $project_id = $c->req->param('project_id');
286 my $schema = $c->dbic_schema('Bio::Chado::Schema');
288 my $data_agreement_cvterm_id_rs = $schema->resultset('Cv::Cvterm')->search( { name => 'data_agreement' });
290 if ($data_agreement_cvterm_id_rs->count() == 0) {
291 $c->stash->{rest} = { error => "No data agreements have been added yet." };
292 return;
295 my $type_id = $data_agreement_cvterm_id_rs->first()->cvterm_id();
297 print STDERR "PROJECTID: $project_id TYPE_ID: $type_id\n";
299 my $projectprop_rs = $schema->resultset('Project::Projectprop')->search(
300 { project_id => $project_id, type_id=>$type_id }
303 if ($projectprop_rs->count() == 0) {
304 $c->stash->{rest} = { error => "No such project $project_id", };
305 return;
307 my $projectprop = $projectprop_rs->first();
308 $c->stash->{rest} = { prop_id => $projectprop->projectprop_id(), text => $projectprop->value() };
312 sub get_all_years : Path('/ajax/breeders/trial/all_years' ) Args(0) {
313 my $self = shift;
314 my $c = shift;
316 my $bp = CXGN::BreedersToolbox::Projects->new({ schema => $c->dbic_schema("Bio::Chado::Schema") });
317 my @years = $bp->get_all_years();
319 $c->stash->{rest} = { years => \@years };
322 sub get_trial_location : Path('/ajax/breeders/trial/location') Args(1) {
323 my $self = shift;
324 my $c = shift;
325 my $trial_id = shift;
327 my $t = CXGN::Trial->new(
329 bcs_schema => $c->dbic_schema("Bio::Chado::Schema"),
330 trial_id => $trial_id
333 if ($t) {
334 $c->stash->{rest} = { location => $t->get_location() };
336 else {
337 $c->stash->{rest} = { error => "The trial with id $trial_id does not exist" };
342 sub get_trial_type : Path('/ajax/breeders/trial/type') Args(1) {
343 my $self = shift;
344 my $c = shift;
345 my $trial_id = shift;
347 my $t = CXGN::Trial->new(
349 bcs_schema => $c->dbic_schema("Bio::Chado::Schema"),
350 trial_id => $trial_id
353 my $type = $t->get_project_type();
354 $c->stash->{rest} = { type => $type };
357 sub get_all_trial_types : Path('/ajax/breeders/trial/alltypes') Args(0) {
358 my $self = shift;
359 my $c = shift;
361 my @types = CXGN::Trial::get_all_project_types($c->dbic_schema("Bio::Chado::Schema"));
363 $c->stash->{rest} = { types => \@types };
366 sub genotype_trial : Path('/ajax/breeders/genotypetrial') Args(0) {
367 my $self = shift;
368 my $c = shift;
371 if (!($c->user()->check_roles('curator') || $c->user()->check_roles('submitter'))) {
372 $c->stash->{rest} = { error => 'You do not have the required privileges to create a genotyping trial.' };
373 return;
376 my $list_id = $c->req->param("list_id");
377 my $name = $c->req->param("name");
378 my $breeding_program_id = $c->req->param("breeding_program");
379 my $description = $c->req->param("description");
380 my $location_id = $c->req->param("location");
381 my $year = $c->req->param("year");
383 my $list = CXGN::List->new( { dbh => $c->dbc->dbh(), list_id => $list_id });
384 my $elements = $list->elements();
386 if (!$name || !$list_id || !$breeding_program_id || !$location_id || !$year) {
387 $c->stash->{rest} = { error => "Please provide all parameters." };
388 return;
391 my $td = CXGN::Trial::TrialDesign->new( { schema => $c->dbic_schema("Bio::Chado::Schema") });
393 $td->set_stock_list($elements);
395 $td->set_block_size(96);
397 $td->set_design_type("genotyping_plate");
398 $td->set_trial_name($name);
399 my $design;
401 eval {
402 $td->calculate_design();
405 if ($@) {
406 $c->stash->{rest} = { error => "Design failed. Error: $@" };
407 return;
410 $design = $td->get_design();
412 if (exists($design->{error})) {
413 $c->stash->{rest} = $design;
414 return;
416 #print STDERR Dumper($design);
418 my $schema = $c->dbic_schema("Bio::Chado::Schema");
419 my $location = $schema->resultset("NaturalDiversity::NdGeolocation")->find( { nd_geolocation_id => $location_id } );
420 if (!$location) {
421 $c->stash->{rest} = { error => "Unknown location" };
422 return;
425 my $breeding_program = $schema->resultset("Project::Project")->find( { project_id => $breeding_program_id });
426 if (!$breeding_program) {
427 $c->stash->{rest} = { error => "Unknown breeding program" };
428 return;
432 my $ct = CXGN::Trial::TrialCreate->new( {
433 chado_schema => $c->dbic_schema("Bio::Chado::Schema"),
434 phenome_schema => $c->dbic_schema("CXGN::Phenome::Schema"),
435 metadata_schema => $c->dbic_schema("CXGN::Metadata::Schema"),
436 dbh => $c->dbc->dbh(),
437 user_name => $c->user()->get_object()->get_username(),
438 trial_year => $year,
439 trial_location => $location->description(),
440 program => $breeding_program->name(),
441 trial_description => $description,
442 design_type => 'genotyping_plate',
443 design => $design,
444 trial_name => $name,
445 is_genotyping => 1,
448 my %message;
450 try {
451 %message = $ct->save_trial();
452 } catch {
453 $c->stash->{rest} = {error => "Error saving trial in the database $_"};
457 $c->stash->{rest} = {
458 message => "Successfully stored the trial.",
459 trial_id => $message{trial_id},
461 #print STDERR Dumper(%message);
465 # this version of the genotype trial requires the upload of a file from the IGD
467 sub igd_genotype_trial : Path('/ajax/breeders/igdgenotypetrial') Args(0) {
468 my $self = shift;
469 my $c = shift;
471 if (!($c->user()->check_roles('curator') || $c->user()->check_roles('submitter'))) {
472 $c->stash->{rest} = { error => 'You do not have the required privileges to create a genotyping trial.' };
473 return;
475 my $schema = $c->dbic_schema("Bio::Chado::Schema");
476 my $list_id = $c->req->param("list_id");
477 #my $name = $c->req->param("name");
478 my $breeding_program_id = $c->req->param("breeding_program");
479 my $description = $c->req->param("description");
480 my $location_id = $c->req->param("location");
481 my $year = $c->req->param("year");
482 my $upload = $c->req->upload('igd_genotyping_trial_upload_file');
483 my $upload_tempfile = $upload->tempname;
484 my $upload_original_name = $upload->filename();
485 my $upload_contents = read_file($upload_tempfile);
487 print STDERR "Parsing IGD file...\n";
489 my $p = CXGN::Trial::ParseUpload->new( { chado_schema => $schema, filename=>$upload_tempfile });
490 $p->load_plugin("ParseIGDFile");
492 my $meta = $p->parse();
494 my $errors = $p->get_parse_errors();
495 if (@{$errors->{'error_messages'}}) {
496 $c->stash->{rest} = { error => "The file has the following problems: ".join ", ", @{$errors->{'error_messages'}}.". Please fix these problems and try again." };
497 print STDERR "Parsing errors in uploaded file. Aborting. (".join ",", @{$errors->{'error_messages'}}.")\n";
498 return;
500 print STDERR "Meta information from genotyping trial file: ".Dumper($meta);
502 my $list = CXGN::List->new( { dbh => $c->dbc->dbh(), list_id => $list_id });
503 my $elements = $list->elements();
505 print STDERR "PARAMS: $upload_original_name, $list_id, $breeding_program_id, $location_id, $year\n";
506 if (!$upload_original_name || !$list_id || !$breeding_program_id || !$location_id || !$year) {
507 $c->stash->{rest} = { error => "Please provide all parameters, including a file." };
508 return;
511 print STDERR "Looking up stock names and converting to IGD accepted names...\n";
513 my $slu = CXGN::Stock::StockLookup->new({ schema => $schema });
515 # remove non-word characters from names as required by
516 # IGD naming conventions. Store new names as synonyms.
518 foreach my $e (@$elements) {
519 my $submission_name = $e;
520 $submission_name =~ s/\W/\_/g;
522 print STDERR "Replacing element $e with $submission_name\n";
523 $slu->set_stock_name($e);
524 my $s = $slu -> get_stock();
525 $slu->set_stock_name($submission_name);
527 print STDERR "Storing synonym $submission_name for $e\n";
528 $slu->set_stock_name($e);
529 eval {
530 #my $rs = $slu->_get_stock_resultset();
531 $s->create_stockprops(
532 { igd_synonym => $submission_name },
533 { autocreate => 1,
534 'cv.name' => 'local',
537 if ($@) {
538 print STDERR "[warning] An error occurred storing the synonym: $submission_name because of $@\n";
542 print STDERR "Creating new trial design...\n";
544 my $td = CXGN::Trial::TrialDesign->new( { schema => $schema });
546 $td->set_stock_list($elements);
547 $td->set_block_size(96);
548 $td->set_blank($meta->{blank_well});
549 $td->set_trial_name($meta->{trial_name});
550 $td->set_design_type("genotyping_plate");
552 my $design;
554 eval {
555 $td->calculate_design();
558 if ($@) {
559 $c->stash->{rest} = { error => "Design failed. Error: $@" };
560 print STDERR "Design failed because of $@\n";
561 return;
564 $design = $td->get_design();
566 if (exists($design->{error})) {
567 $c->stash->{rest} = $design;
568 return;
570 #print STDERR Dumper($design);
572 my $location = $schema->resultset("NaturalDiversity::NdGeolocation")->find( { nd_geolocation_id => $location_id } );
573 if (!$location) {
574 $c->stash->{rest} = { error => "Unknown location" };
575 return;
578 my $breeding_program = $schema->resultset("Project::Project")->find( { project_id => $breeding_program_id });
579 if (!$breeding_program) {
580 $c->stash->{rest} = { error => "Unknown breeding program" };
581 return;
584 print STDERR "Creating the trial...\n";
586 my $ct = CXGN::Trial::TrialCreate->new( {
587 chado_schema => $schema,
588 phenome_schema => $c->dbic_schema("CXGN::Phenome::Schema"),
589 metadata_schema => $c->dbic_schema("CXGN::Metadata::Schema"),
590 dbh => $c->dbc->dbh(),
591 user_name => $c->user()->get_object()->get_username(),
592 trial_year => $year,
593 trial_location => $location->description(),
594 program => $breeding_program->name(),
595 trial_description => $description || "",
596 design_type => 'genotyping_plate',
597 design => $design,
598 trial_name => $meta->{trial_name},
599 is_genotyping => 1,
600 genotyping_user_id => $meta->{user_id} || "unknown",
601 genotyping_project_name => $meta->{project_name} || "unknown",
604 my %message;
606 eval {
607 %message = $ct->save_trial();
610 if ($@ || exists($message{error})) {
611 $c->stash->{rest} = {
612 error => "Error saving the trial. $@ $message{error}"
614 print STDERR "Error saving trial\n";
615 return;
617 $c->stash->{rest} = {
618 message => "Successfully stored the trial.",
619 trial_id => $message{trial_id},
621 #print STDERR Dumper(%message);