4 SGN::Controller::AJAX::PhenotypesUpload - a REST controller class to provide the
5 backend for uploading phenotype spreadsheets
9 Uploading Phenotype Spreadsheets
13 Jeremy Edwards <jde22@cornell.edu>
14 Naama Menda <nm249@cornell.edu>
15 Alex Ogbonna <aco46@cornell.edu>
16 Nicolas Morales <nm529@cornell.edu>
20 package SGN
::Controller
::AJAX
::PhenotypesUpload
;
26 use File
::Spec
::Functions
;
29 use CXGN
::Phenotypes
::ParseUpload
;
30 use CXGN
::Phenotypes
::StorePhenotypes
;
31 use List
::MoreUtils qw
/any /;
33 BEGIN { extends
'Catalyst::Controller::REST' }
36 default => 'application/json',
38 map => { 'application/json' => 'JSON', 'text/html' => 'JSON' },
42 sub upload_phenotype_verify
: Path
('/ajax/phenotype/upload_verify') : ActionClass
('REST') { }
43 sub upload_phenotype_verify_POST
: Args
(1) {
44 my ($self, $c, $file_type) = @_;
45 my $schema = $c->dbic_schema("Bio::Chado::Schema");
46 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema");
47 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema");
49 my ($success_status, $error_status, $parsed_data, $plots, $traits, $phenotype_metadata, $timestamp_included, $overwrite_values, $image_zip, $user_id) = _prep_upload
($c, $file_type, $schema);
50 if (scalar(@
$error_status)>0) {
51 $c->stash->{rest
} = {success
=> $success_status, error
=> $error_status };
56 if ($timestamp_included) {
59 my $store_phenotypes = CXGN
::Phenotypes
::StorePhenotypes
->new(
61 metadata_schema
=>$metadata_schema,
62 phenome_schema
=>$phenome_schema,
66 values_hash
=>$parsed_data,
67 has_timestamps
=>$timestamp,
68 metadata_hash
=>$phenotype_metadata,
69 image_zipfile_path
=>$image_zip,
73 my ($verified_warning, $verified_error) = $store_phenotypes->verify();
74 if ($verified_error) {
75 push @
$error_status, $verified_error;
76 $c->stash->{rest
} = {success
=> $success_status, error
=> $error_status };
79 if ($verified_warning) {
80 push @
$warning_status, $verified_warning;
82 push @
$success_status, "File data verified. Plot names and trait names are valid.";
84 $c->stash->{rest
} = {success
=> $success_status, warning
=> $warning_status, error
=> $error_status};
87 sub upload_phenotype_store
: Path
('/ajax/phenotype/upload_store') : ActionClass
('REST') { }
88 sub upload_phenotype_store_POST
: Args
(1) {
89 my ($self, $c, $file_type) = @_;
90 my $schema = $c->dbic_schema("Bio::Chado::Schema");
91 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema");
92 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema");
94 my ($success_status, $error_status, $parsed_data, $plots, $traits, $phenotype_metadata, $timestamp_included, $overwrite_values, $image_zip, $user_id) = _prep_upload
($c, $file_type, $schema);
95 if (scalar(@
$error_status)>0) {
96 $c->stash->{rest
} = {success
=> $success_status, error
=> $error_status };
100 if ($overwrite_values) {
104 if ($timestamp_included) {
108 my $store_phenotypes = CXGN
::Phenotypes
::StorePhenotypes
->new(
110 metadata_schema
=>$metadata_schema,
111 phenome_schema
=>$phenome_schema,
115 values_hash
=>$parsed_data,
116 has_timestamps
=>$timestamp,
117 overwrite_values
=>$overwrite,
118 metadata_hash
=>$phenotype_metadata,
119 image_zipfile_path
=>$image_zip,
122 #upload_phenotype_store function redoes the same verification that upload_phenotype_verify does before actually uploading. maybe this should be commented out.
123 #my ($verified_warning, $verified_error) = $store_phenotypes->verify($c,$plots,$traits, $parsed_data, $phenotype_metadata);
124 #if ($verified_error) {
125 #push @$error_status, $verified_error;
126 #$c->stash->{rest} = {success => $success_status, error => $error_status };
129 #push @$success_status, "File data verified. Plot names and trait names are valid.";
131 my ($stored_phenotype_error, $stored_phenotype_success) = $store_phenotypes->store();
132 if ($stored_phenotype_error) {
133 push @
$error_status, $stored_phenotype_error;
134 $c->stash->{rest
} = {success
=> $success_status, error
=> $error_status};
137 if ($stored_phenotype_success) {
138 push @
$success_status, $stored_phenotype_success;
142 my $image = SGN
::Image
->new( $c->dbc->dbh, undef, $c );
143 my $image_error = $image->upload_fieldbook_zipfile($image_zip, $user_id);
145 push @
$error_status, $image_error;
149 push @
$success_status, "Metadata saved for archived file.";
151 $c->stash->{rest
} = {success
=> $success_status, error
=> $error_status};
155 my ($c, $file_type, $schema) = @_;
159 my $user = $c->user();
161 push @error_status, 'Must be logged in to upload phenotypes!';
162 return (\
@success_status, \
@error_status);
165 my $user_id = $c->can('user_exists') ?
$c->user->get_object->get_sp_person_id : $c->sp_person_id;
166 my $parser = CXGN
::Phenotypes
::ParseUpload
->new();
167 my $timestamp_included;
171 my $metadata_file_type;
174 if ($file_type eq "spreadsheet") {
175 print STDERR
"Spreadsheet \n";
176 my $spreadsheet_format = $c->req->param('upload_spreadsheet_phenotype_file_format'); #simple or detailed
177 if ($spreadsheet_format eq 'detailed'){
178 $validate_type = "phenotype spreadsheet";
180 if ($spreadsheet_format eq 'simple'){
181 $validate_type = "phenotype spreadsheet simple";
183 $subdirectory = "spreadsheet_phenotype_upload";
184 $metadata_file_type = "spreadsheet phenotype file";
185 $timestamp_included = $c->req->param('upload_spreadsheet_phenotype_timestamp_checkbox');
186 $data_level = $c->req->param('upload_spreadsheet_phenotype_data_level') || 'plots';
187 $upload = $c->req->upload('upload_spreadsheet_phenotype_file_input');
189 elsif ($file_type eq "fieldbook") {
190 print STDERR
"Fieldbook \n";
191 $subdirectory = "tablet_phenotype_upload";
192 $validate_type = "field book";
193 $metadata_file_type = "tablet phenotype file";
194 $timestamp_included = 1;
195 $upload = $c->req->upload('upload_fieldbook_phenotype_file_input');
196 $image_zip = $c->req->upload('upload_fieldbook_phenotype_images_zipfile');
197 $data_level = $c->req->param('upload_fieldbook_phenotype_data_level') || 'plots';
199 elsif ($file_type eq "datacollector") {
200 print STDERR
"Datacollector \n";
201 $subdirectory = "data_collector_phenotype_upload";
202 $validate_type = "datacollector spreadsheet";
203 $metadata_file_type = "data collector phenotype file";
204 $timestamp_included = $c->req->param('upload_datacollector_phenotype_timestamp_checkbox');
205 $upload = $c->req->upload('upload_datacollector_phenotype_file_input');
208 my $user_type = $user->get_object->get_user_type();
209 if ($user_type ne 'submitter' && $user_type ne 'curator') {
210 push @error_status, 'Must have submitter privileges to upload phenotypes! Please contact us!';
211 return (\
@success_status, \
@error_status);
214 my $overwrite_values = $c->req->param('phenotype_upload_overwrite_values');
215 if ($overwrite_values) {
216 #print STDERR $user_type."\n";
217 if ($user_type ne 'curator') {
218 push @error_status, 'Must be a curator to overwrite values! Please contact us!';
219 return (\
@success_status, \
@error_status);
223 my $upload_original_name = $upload->filename();
224 my $upload_tempfile = $upload->tempname;
225 my %phenotype_metadata;
226 my $time = DateTime
->now();
227 my $timestamp = $time->ymd()."_".$time->hms();
229 my $uploader = CXGN
::UploadFile
->new({
230 tempfile
=> $upload_tempfile,
231 subdirectory
=> $subdirectory,
232 archive_path
=> $c->config->{archive_path
},
233 archive_filename
=> $upload_original_name,
234 timestamp
=> $timestamp,
236 user_role
=> $user_type
238 my $archived_filename_with_path = $uploader->archive();
239 my $md5 = $uploader->get_md5($archived_filename_with_path);
240 if (!$archived_filename_with_path) {
241 push @error_status, "Could not save file $upload_original_name in archive.";
242 return (\
@success_status, \
@error_status);
244 push @success_status, "File $upload_original_name saved in archive.";
246 unlink $upload_tempfile;
247 #print STDERR "Archived Phenotype File: $archived_filename_with_path\n";
249 my $archived_image_zipfile_with_path;
251 my $upload_original_name = $image_zip->filename();
252 my $upload_tempfile = $image_zip->tempname;
253 my $uploader = CXGN
::UploadFile
->new({
254 tempfile
=> $upload_tempfile,
255 subdirectory
=> $subdirectory."_images",
256 archive_path
=> $c->config->{archive_path
},
257 archive_filename
=> $upload_original_name,
258 timestamp
=> $timestamp,
260 user_role
=> $user_type
262 $archived_image_zipfile_with_path = $uploader->archive();
263 my $md5 = $uploader->get_md5($archived_image_zipfile_with_path);
264 if (!$archived_image_zipfile_with_path) {
265 push @error_status, "Could not save images zipfile $upload_original_name in archive.";
266 return (\
@success_status, \
@error_status);
268 push @success_status, "Images Zip File $upload_original_name saved in archive.";
270 unlink $upload_tempfile;
271 #print STDERR "Archived Zipfile: $archived_image_zipfile_with_path\n";
274 ## Validate and parse uploaded file
275 my $validate_file = $parser->validate($validate_type, $archived_filename_with_path, $timestamp_included, $data_level, $schema);
276 if (!$validate_file) {
277 push @error_status, "Archived file not valid: $upload_original_name.";
278 return (\
@success_status, \
@error_status);
280 if ($validate_file == 1){
281 push @success_status, "File valid: $upload_original_name.";
283 if ($validate_file->{'error'}) {
284 push @error_status, $validate_file->{'error'};
286 return (\
@success_status, \
@error_status);
290 $phenotype_metadata{'archived_file'} = $archived_filename_with_path;
291 $phenotype_metadata{'archived_file_type'} = $metadata_file_type;
292 my $operator = $user->get_object()->get_username();
293 $phenotype_metadata{'operator'} = $operator;
294 $phenotype_metadata{'date'} = $timestamp;
296 my $parsed_file = $parser->parse($validate_type, $archived_filename_with_path, $timestamp_included, $data_level, $schema);
298 push @error_status, "Error parsing file $upload_original_name.";
299 return (\
@success_status, \
@error_status);
301 if ($parsed_file->{'error'}) {
302 push @error_status, $parsed_file->{'error'};
307 if (scalar(@error_status) == 0) {
308 if ($parsed_file && !$parsed_file->{'error'}) {
309 %parsed_data = %{$parsed_file->{'data'}};
310 @plots = @
{$parsed_file->{'plots'}};
311 @traits = @
{$parsed_file->{'traits'}};
312 push @success_status, "File data successfully parsed.";
316 return (\
@success_status, \
@error_status, \
%parsed_data, \
@plots, \
@traits, \
%phenotype_metadata, $timestamp_included, $overwrite_values, $archived_image_zipfile_with_path, $user_id);
319 sub update_plot_phenotype
: Path
('/ajax/phenotype/plot_phenotype_upload') : ActionClass
('REST') { }
320 sub update_plot_phenotype_POST
: Args
(0) {
323 my $plot_name = $c->req->param("plot_name");
324 my $trait_id = $c->req->param("trait");
325 my $trait_value = $c->req->param("trait_value");
326 my $trait_list_option = $c->req->param("trait_list_option");
327 my $time = DateTime
->now();
328 my $timestamp = $time->ymd()."_".$time->hms();
329 my $dbh = $c->dbc->dbh();
330 my $schema = $c->dbic_schema("Bio::Chado::Schema");
331 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema");
332 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema");
333 my (@plots, @traits, %data, $trait);
334 my $accession_cvterm_id = SGN
::Model
::Cvterm
->get_cvterm_row($schema, 'accession', 'stock_type' )->cvterm_id();
335 print "MY LIST OPTION: $trait_list_option\n";
336 my $plot = $schema->resultset("Stock::Stock")->find( { uniquename
=>$plot_name });
337 my $plot_type_id = $plot->type_id();
340 print STDERR
"User not logged in... not uploading phenotype.\n";
341 $c->stash->{rest
} = {error
=> "You need to be logged in to upload phenotype." };
344 if (!any
{ $_ eq "curator" || $_ eq "submitter" } ($c->user()->roles) ) {
345 $c->stash->{rest
} = {error
=> "You have insufficient privileges to upload phenotype." };
349 if ($plot_type_id == $accession_cvterm_id) {
350 print "You are using accessions\n";
351 $c->stash->{rest
} = {error
=> "Used only for Plot Phenotyping."};
355 if (!$trait_list_option){
356 my $h = $dbh->prepare("SELECT cvterm.cvterm_id AS trait_id, (((cvterm.name::text || '|'::text) || db.name::text) || ':'::text) || dbxref.accession::text AS trait_name FROM cvterm JOIN dbxref ON cvterm.dbxref_id = dbxref.dbxref_id JOIN db ON dbxref.db_id = db.db_id WHERE db.db_id = (( SELECT dbxref_1.db_id FROM stock JOIN nd_experiment_stock USING (stock_id) JOIN nd_experiment_phenotype USING (nd_experiment_id) JOIN phenotype USING (phenotype_id) JOIN cvterm cvterm_1 ON phenotype.cvalue_id = cvterm_1.cvterm_id JOIN dbxref dbxref_1 ON cvterm_1.dbxref_id = dbxref_1.dbxref_id LIMIT 1)) AND cvterm_id =? GROUP BY cvterm.cvterm_id, ((((cvterm.name::text || '|'::text) || db.name::text) || ':'::text) || dbxref.accession::text);");
357 $h->execute($trait_id);
358 while (my ($id, $trait_name) = $h->fetchrow_array()) {
359 $trait = $trait_name;
365 push @plots, $plot_name;
366 push @traits, $trait;
368 $data{$plot_name}->{$trait} = [$trait_value,$timestamp];
370 my %phenotype_metadata;
371 $phenotype_metadata{'archived_file'} = 'none';
372 $phenotype_metadata{'archived_file_type'}="direct phenotyping";
373 $phenotype_metadata{'operator'}=$c->user()->get_object()->get_sp_person_id();
374 $phenotype_metadata{'date'}="$timestamp";
375 my $user_id = $c->can('user_exists') ?
$c->user->get_object->get_sp_person_id : $c->sp_person_id;
377 my $store_phenotypes = CXGN
::Phenotypes
::StorePhenotypes
->new(
379 metadata_schema
=>$metadata_schema,
380 phenome_schema
=>$phenome_schema,
383 trait_list
=>\
@traits,
386 overwrite_values
=> 1,
387 metadata_hash
=>\
%phenotype_metadata,
390 my ($verified_warning, $verified_error) = $store_phenotypes->verify();
391 if ($verified_error){
392 $c->stash->{rest
} = {error
=> $verified_error};
396 my ($store_error, $store_success) = $store_phenotypes->store();
398 $c->stash->{rest
} = {error
=> $store_error};
402 $c->stash->{rest
} = {success
=> 1};
405 sub retrieve_plot_phenotype
: Path
('/ajax/phenotype/plot_phenotype_retrieve') : ActionClass
('REST') { }
406 sub retrieve_plot_phenotype_POST
: Args
(0) {
409 my $dbh = $c->dbc->dbh();
410 my $schema = $c->dbic_schema("Bio::Chado::Schema");
411 my $plot_name = $c->req->param("plot_name");
412 my $trait_id = $c->req->param("trait");
413 my $trait_list_option = $c->req->param("trait_list_option");
415 my $stock = $schema->resultset("Stock::Stock")->find( { uniquename
=>$plot_name });
416 my $stock_id = $stock->stock_id();
418 if ($trait_list_option){
419 my $h = $dbh->prepare("SELECT cvterm.cvterm_id AS trait_id, (((cvterm.name::text || '|'::text) || db.name::text) || ':'::text) || dbxref.accession::text AS trait_name FROM cvterm JOIN dbxref ON cvterm.dbxref_id = dbxref.dbxref_id JOIN db ON dbxref.db_id = db.db_id WHERE db.db_id = (( SELECT dbxref_1.db_id FROM stock JOIN nd_experiment_stock USING (stock_id) JOIN nd_experiment_phenotype USING (nd_experiment_id) JOIN phenotype USING (phenotype_id) JOIN cvterm cvterm_1 ON phenotype.cvalue_id = cvterm_1.cvterm_id JOIN dbxref dbxref_1 ON cvterm_1.dbxref_id = dbxref_1.dbxref_id LIMIT 1)) AND (((cvterm.name::text || '|'::text) || db.name::text) || ':'::text) || dbxref.accession::text =? GROUP BY cvterm.cvterm_id, ((((cvterm.name::text || '|'::text) || db.name::text) || ':'::text) || dbxref.accession::text);");
420 $h->execute($trait_id);
421 while (my ($id, $trait_name) = $h->fetchrow_array()) {
426 my $h = $dbh->prepare("SELECT phenotype.value FROM stock
427 JOIN nd_experiment_stock USING(stock_id)
428 JOIN nd_experiment_phenotype USING(nd_experiment_id)
429 JOIN phenotype USING(phenotype_id)
430 WHERE cvalue_id =? and stock_id=?;"
432 $h->execute($trait_id,$stock_id);
433 while (my ($plot_value) = $h->fetchrow_array()) {
434 $trait_value = $plot_value;
437 $c->stash->{rest
} = {trait_value
=> $trait_value};