Added eval; site now shows clean dataset missing message instead of server error...
[sgn.git] / lib / SGN / Controller / AJAX / FieldBook.pm
blob2b1255d3b54b1d5dd0dec221c794b222373d4c7b
2 =head1 NAME
4 SGN::Controller::AJAX::FieldBook - a REST controller class to provide the
5 backend for field book operations
7 =head1 DESCRIPTION
9 Creating and viewing trials
11 =head1 AUTHOR
13 Jeremy Edwards <jde22@cornell.edu>
15 =cut
17 package SGN::Controller::AJAX::FieldBook;
19 use Moose;
20 use List::MoreUtils qw /any /;
21 use Scalar::Util qw(looks_like_number);
22 use DateTime;
23 use Try::Tiny;
24 use File::Basename qw | basename dirname|;
25 use File::Copy;
26 use File::Slurp;
27 use File::Spec::Functions;
28 use Digest::MD5;
29 use JSON -support_by_pp;
30 use Spreadsheet::WriteExcel;
31 use SGN::View::Trial qw/design_layout_view design_info_view/;
32 use CXGN::Location::LocationLookup;
33 use CXGN::Stock::StockLookup;
34 use CXGN::UploadFile;
35 use CXGN::Fieldbook::TraitInfo;
36 use CXGN::Fieldbook::DownloadTrial;
37 use SGN::Model::Cvterm;
38 use CXGN::List;
39 use CXGN::List::Validate;
40 use CXGN::List::Transform;
41 use Data::Dumper;
43 BEGIN { extends 'Catalyst::Controller::REST' }
45 __PACKAGE__->config(
46 default => 'application/json',
47 stash_key => 'rest',
48 map => { 'application/json' => 'JSON' },
52 sub create_fieldbook_from_trial : Path('/ajax/fieldbook/create') : ActionClass('REST') { }
54 sub create_fieldbook_from_trial_POST : Args(0) {
55 my ($self, $c) = @_;
56 my $sp_person_id = $c->user() ? $c->user->get_object()->get_sp_person_id() : undef;
57 my $schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
58 my $trial_id = $c->req->param('trial_id');
59 my $data_level = $c->req->param('data_level') || 'plots';
60 my $treatment_project_ids = $c->req->param('treatment_project_id') ? [$c->req->param('treatment_project_id')] : [];
61 my $metadata_schema = $c->dbic_schema('CXGN::Metadata::Schema', undef, $sp_person_id);
62 my $phenome_schema = $c->dbic_schema('CXGN::Phenome::Schema', undef, $sp_person_id);
64 chomp($trial_id);
65 if (!$c->user()) {
66 $c->stash->{rest} = {error => "You need to be logged in to create a field book" };
67 return;
69 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) {
70 $c->stash->{rest} = {error => "You have insufficient privileges to create a field book." };
71 return;
73 if (!$trial_id) {
74 $c->stash->{rest} = {error => "No trial ID supplied." };
75 return;
77 my $trial = $schema->resultset('Project::Project')->find({project_id => $trial_id});
78 if (!$trial) {
79 $c->stash->{rest} = {error => "Trial does not exist with id $trial_id." };
80 return;
82 if ($data_level eq 'plants') {
83 my $trial = CXGN::Trial->new( { bcs_schema => $schema, trial_id => $trial_id });
84 if (!$trial->has_plant_entries()){
85 $c->stash->{rest} = {error => "Trial does not have plant entries. You must first create plant entries." };
86 return;
89 if ($data_level eq 'subplots' || $data_level eq 'plants_subplots') {
90 my $trial = CXGN::Trial->new( { bcs_schema => $schema, trial_id => $trial_id });
91 if (!$trial->has_subplot_entries()) {
92 $c->stash->{rest} = {error => "Trial does not have subplot entries." };
93 return;
97 my $trial_stock_type;
98 if (!defined($c->req->param('trial_stock_type'))) {
99 $trial_stock_type = 'accession';
100 } else {
101 $trial_stock_type = $c->req->param('trial_stock_type');
104 my $original_selected_columns = $c->req->param('selected_columns') ? decode_json $c->req->param('selected_columns') : {};
106 my %modified_columns = %{$original_selected_columns};
107 if (exists $modified_columns{'family_name'}) {
108 delete $modified_columns{'family_name'};
109 $modified_columns{'accession_name'} = 1;
111 if (exists $modified_columns{'cross_unique_id'}) {
112 delete $modified_columns{'cross_unique_id'};
113 $modified_columns{'accession_name'} = 1;
115 my $selected_columns = \%modified_columns;
117 # print STDERR "ORIGINAL SELECTED COLUMNS =".Dumper($original_selected_columns)."\n";
118 # print STDERR "MODIFIED COLUMNS =".Dumper(\%modified_columns)."\n";
119 my $include_measured = $c->req->param('include_measured') || '';
120 my $all_stats = $c->req->param('all_stats') || '';
121 my $use_synonyms = $c->req->param('use_synonyms') || '';
122 my $selected_trait_list_id = $c->req->param('trait_list');
123 my @selected_traits;
124 if ($selected_trait_list_id){
125 my $list = CXGN::List->new({ dbh => $c->dbc->dbh, list_id => $selected_trait_list_id });
126 my @trait_list = @{$list->elements()};
127 my $validator = CXGN::List::Validate->new();
128 my @absent_traits = @{$validator->validate($schema, 'traits', \@trait_list)->{'missing'}};
129 if (scalar(@absent_traits)>0){
130 $c->stash->{rest} = {error => "Trait list is not valid because of these terms: ".join ',',@absent_traits };
131 $c->detach();
133 my $lt = CXGN::List::Transform->new();
134 @selected_traits = @{$lt->transform($schema, "traits_2_trait_ids", \@trait_list)->{transform}};
137 my $dir = $c->tempfiles_subdir('/other');
138 my $tempfile = $c->config->{basepath}."/".$c->tempfile( TEMPLATE => 'other/excelXXXX');
140 my $create_fieldbook = CXGN::Fieldbook::DownloadTrial->new({
141 bcs_schema => $schema,
142 metadata_schema => $metadata_schema,
143 phenome_schema => $phenome_schema,
144 trial_id => $trial_id,
145 tempfile => $tempfile,
146 archive_path => $c->config->{archive_path},
147 user_id => $c->user()->get_object()->get_sp_person_id(),
148 user_name => $c->user()->get_object()->get_username(),
149 data_level => $data_level,
150 treatment_project_ids => $treatment_project_ids,
151 selected_columns => $selected_columns,
152 include_measured => $include_measured,
153 all_stats => $all_stats,
154 use_synonyms => $use_synonyms,
155 selected_trait_ids => \@selected_traits,
156 trial_stock_type => $trial_stock_type,
159 my $create_fieldbook_return = $create_fieldbook->download();
160 my $error;
161 if ($create_fieldbook_return->{'error_messages'}){
162 $error = join ',', @{$create_fieldbook_return->{'error_messages'}};
165 $c->stash->{rest} = {
166 error_string => $error,
167 success => 1,
168 result => $create_fieldbook_return->{'result'},
169 file => $create_fieldbook_return->{'file'},
170 file_id => $create_fieldbook_return->{'file_id'},
174 sub create_trait_file_for_field_book : Path('/ajax/fieldbook/traitfile/create') : ActionClass('REST') { }
176 sub create_trait_file_for_field_book_POST : Args(0) {
177 my ($self, $c) = @_;
179 if (!$c->user()) {
180 $c->stash->{rest} = {error => "You need to be logged in to create a field book" };
181 return;
183 if (!any { $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) {
184 $c->stash->{rest} = {error => "You have insufficient privileges to create a field book." };
185 return;
188 my @trait_list;
189 my $trait_file_name = $c->req->param('trait_file_name');
190 my $include_notes = $c->req->param('include_notes');
191 my $user_id = $c->user()->get_object()->get_sp_person_id();
192 my $user_name = $c->user()->get_object()->get_username();
193 my $time = DateTime->now();
194 my $timestamp = $time->ymd()."_".$time->hms();
195 my $subdirectory_name = "tablet_trait_files";
196 my $archived_file_name = catfile($user_id, $subdirectory_name,$timestamp."_".$trait_file_name.".trt");
197 my $archive_path = $c->config->{archive_path};
198 my $file_destination = catfile($archive_path, $archived_file_name);
199 my $dbh = $c->dbc->dbh();
200 my @trait_ids;
202 if ($c->req->param('selected_listed')) {
203 @trait_list = @{_parse_list_from_json($c->req->param('trait_list'))};
204 @trait_ids = @{_parse_list_from_json($c->req->param('trait_ids'))};
205 } else {
206 @trait_list = @{_parse_list_from_json($c->req->param('trait_list'))};
207 @trait_ids = $c->req->param('trait_ids');
210 if (!-d $archive_path) {
211 mkdir $archive_path;
214 if (! -d catfile($archive_path, $user_id)) {
215 mkdir (catfile($archive_path, $user_id));
218 if (! -d catfile($archive_path, $user_id,$subdirectory_name)) {
219 mkdir (catfile($archive_path, $user_id, $subdirectory_name));
221 print STDERR Dumper($file_destination);
222 open(my $FILE, "> :encoding(UTF-8)", $file_destination) or die $!;
223 my $chado_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $user_id);
224 print $FILE "trait,format,defaultValue,minimum,maximum,details,categories,isVisible,realPosition\n";
225 my $order = 0;
227 foreach my $term (@trait_list) {
228 #print STDERR "term is $term\n";
229 my @parts = split (/\|/ , $term);
230 my ($db_name, $accession) = split ":", pop @parts;
231 my $trait_name = join ("|", @parts);
232 #print STDERR "trait name is $trait_name, full cvterm accession is $full_cvterm_accession\n";
233 #my ( $db_name , $accession ) = split (/:/ , $full_cvterm_accession);
235 $accession =~ s/\s+$//;
236 $accession =~ s/^\s+//;
237 $db_name =~ s/\s+$//;
238 $db_name =~ s/^\s+//;
240 my $cvterm = CXGN::Chado::Cvterm->new( $dbh, $trait_ids[$order] );
241 my $synonym = $cvterm->get_uppercase_synonym();
242 my $name;
243 if($c->config->{fieldbook_trait_synonym}) {
244 print STDERR "synonym: $synonym, trait_name: $trait_name\n";
245 $name = $synonym || $trait_name; # use uppercase synonym if defined, otherwise use full trait name
246 } else {
247 print STDERR "trait_name: $trait_name\n";
248 $name = $trait_name;
250 $order++;
252 #get trait info
254 my $trait_info_lookup = CXGN::Fieldbook::TraitInfo
255 ->new({
256 chado_schema => $chado_schema,
257 db_name => $db_name,
258 trait_accession => $accession,
260 my $trait_info_string = $trait_info_lookup->get_trait_info($trait_name);
262 #return error if not $trait_info_string;
263 #print line with trait info
264 #print FILE "$trait_name:$db_name:$accession,text,,,,,,TRUE,$order\n";
265 #print STDERR " Adding line \"$name\t\t\t|$db_name:$accession\",$trait_info_string,\"TRUE\",\"$order\" to trait file\n";
266 print $FILE "\"$name\t\t\t|$db_name:$accession\",$trait_info_string,\"TRUE\",\"$order\"\n";
269 if ($include_notes eq 'true') {
270 $order++;
271 #print STDERR " Adding notes line \"notes\",\"text\",\"\",\"\",\"\",\"Additional observations for future reference\",\"\",\"TRUE\",\"$order\"\n";
272 print $FILE "\"notes\",\"text\",\"\",\"\",\"\",\"Additional observations for future reference\",\"\",\"TRUE\",\"$order\"\n";
275 close $FILE;
277 open(my $F, "<", $file_destination) || die "Can't open file ";
278 binmode $F;
279 my $md5 = Digest::MD5->new();
280 $md5->addfile($F);
281 close($F);
283 my $metadata_schema = $c->dbic_schema('CXGN::Metadata::Schema', undef, $user_id);
285 my $md_row = $metadata_schema->resultset("MdMetadata")->create({
286 create_person_id => $user_id,
288 $md_row->insert();
290 my $file_row = $metadata_schema->resultset("MdFiles")->create({
291 basename => basename($file_destination),
292 dirname => dirname($file_destination),
293 filetype => 'tablet trait file',
294 md5checksum => $md5->hexdigest(),
295 metadata_id => $md_row->metadata_id(),
297 $file_row->insert();
299 my $id = $file_row->file_id();
301 $c->stash->{rest} = {success => "1", file_id => $id, };
306 sub _parse_list_from_json {
307 my $list_json = shift;
308 my $json = new JSON;
309 if ($list_json) {
310 #my $decoded_list = $json->allow_nonref->utf8->relaxed->escape_slash->loose->allow_singlequote->allow_barekey->decode($list_json);
311 my $decoded_list = decode_json($list_json);
312 my @array_of_list_items = @{$decoded_list};
313 return \@array_of_list_items;
315 else {
316 return;