4 SGN::Controller::AJAX::ODK - a REST controller class to provide the
5 backend for ODK services
13 package SGN
::Controller
::AJAX
::ODK
;
16 use List
::MoreUtils qw
/any /;
19 use CXGN
::Phenome
::Schema
;
20 use Bio
::Chado
::Schema
;
22 use SGN
::Model
::Cvterm
;
26 use CXGN
::ODK
::Crosses
;
28 use File
::Spec
::Functions qw
/ catfile catdir/;
29 use File
::Path
qw(make_path);
32 BEGIN { extends
'Catalyst::Controller::REST' }
35 default => 'application/json',
37 map => { 'application/json' => 'JSON' },
41 sub get_phenotyping_data
: Path
('/ajax/odk/get_phenotyping_data') : ActionClass
('REST') { }
43 sub get_phenotyping_data_GET
{
44 my ( $self, $c ) = @_;
45 my $odk_phenotyping_data_service_name = $c->config->{odk_phenotyping_data_service_name
};
46 my $odk_phenotyping_data_service_username = $c->config->{odk_phenotyping_data_service_username
};
47 my $odk_phenotyping_data_service_password = $c->config->{odk_phenotyping_data_service_password
};
48 if ($odk_phenotyping_data_service_name eq 'SMAP'){
49 my $ua = LWP
::UserAgent
->new;
50 my $server_endpoint = "https://".$odk_phenotyping_data_service_username.":".$odk_phenotyping_data_service_password."\@bio.smap.com.au/api/v1/data";
51 print STDERR
$server_endpoint."\n";
53 my $resp = $ua->get($server_endpoint);
54 if ($resp->is_success) {
55 my $message = $resp->decoded_content;
56 my $message_hash = decode_json
$message;
57 print STDERR Dumper
$message_hash;
59 print STDERR Dumper
$resp;
63 $c->stash->{rest
} = { error
=> 'Error: We only support SMAP as an ODK phenotyping service for now.' };
66 $c->stash->{rest
} = { success
=> 1 };
69 sub get_crossing_available_forms
: Path
('/ajax/odk/get_crossing_available_forms') : ActionClass
('REST') { }
71 sub get_crossing_available_forms_GET
{
72 my ( $self, $c ) = @_;
73 my $sp_person_id = $c->user() ?
$c->user->get_object()->get_sp_person_id() : undef;
74 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $sp_person_id);
75 my $dbh = $bcs_schema->storage->dbh;
76 my $odk_crossing_data_service_name = $c->config->{odk_crossing_data_service_name
};
77 my $session_id = $c->req->param('session_id');
83 my $dbh = $c->dbc->dbh;
84 my @user_info = CXGN
::Login
->new($dbh)->query_from_cookie($session_id);
86 $c->stash->{rest
} = {error
=>'You must be logged in to look at ONA forms!'};
89 $user_id = $user_info[0];
90 $user_role = $user_info[1];
91 my $p = CXGN
::People
::Person
->new($dbh, $user_id);
92 $user_name = $p->get_username;
95 $c->stash->{rest
} = {error
=>'You must be logged in to look at ONA forms!'};
98 $user_id = $c->user()->get_object()->get_sp_person_id();
99 $user_name = $c->user()->get_object()->get_username();
100 $user_role = $c->user->get_object->get_user_type();
104 if ($odk_crossing_data_service_name eq 'ONA'){
105 my $ua = LWP
::UserAgent
->new;
106 $ua->credentials( 'api.ona.io:443', 'DJANGO', $c->config->{odk_crossing_data_service_username
}, $c->config->{odk_crossing_data_service_password
} );
107 my $login_resp = $ua->get("https://api.ona.io/api/v1/user.json");
108 my $server_endpoint = "https://api.ona.io/api/v1/data";
109 my $resp = $ua->get($server_endpoint);
111 if ($resp->is_success) {
112 my $message = $resp->decoded_content;
113 $message_hash = decode_json
$message;
116 $c->stash->{rest
} = { success
=> 1, forms
=>$message_hash };
119 sub get_crossing_data
: Path
('/ajax/odk/get_crossing_data') : ActionClass
('REST') { }
121 sub get_crossing_data_GET
{
122 my ( $self, $c ) = @_;
123 my $form_id = $c->req->param('form_id');
124 print STDERR Dumper
$form_id;
125 my $session_id = $c->req->param("sgn_session_id");
130 my $dbh = $c->dbc->dbh;
131 my @user_info = CXGN
::Login
->new($dbh)->query_from_cookie($session_id);
133 $c->stash->{rest
} = {error
=>'You must be logged in to request ODK crossing data import!'};
136 $user_id = $user_info[0];
137 $user_role = $user_info[1];
138 my $p = CXGN
::People
::Person
->new($dbh, $user_id);
139 $user_name = $p->get_username;
142 $c->stash->{rest
} = {error
=>'You must be logged in to request ODK crossing data import!'};
145 $user_id = $c->user()->get_object()->get_sp_person_id();
146 $user_name = $c->user()->get_object()->get_username();
147 $user_role = $c->user->get_object->get_user_type();
149 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $user_id);
150 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $user_id);
151 my $phenome_schema = $c->dbic_schema("CXGN::Phenome::Schema", undef, $user_id);
152 my $tempfiles_dir = $c->tempfiles_subdir('ODK_ONA_cross_info');
153 my ($cross_wishlist_temp_file, $cross_wishlist_uri1) = $c->tempfile( TEMPLATE
=> 'ODK_ONA_cross_info/ODK_ONA_cross_wishlist_downloadXXXXX');
154 my $cross_wishlist_temp_file_path = $cross_wishlist_temp_file->filename;
155 my ($germplasm_info_temp_file, $germplasm_info_uri1) = $c->tempfile( TEMPLATE
=> 'ODK_ONA_cross_info/ODK_ONA_germplasm_info_downloadXXXXX');
156 my $germplasm_info_temp_file_path = $germplasm_info_temp_file->filename;
158 my $progress_tree_dir = catdir
($c->site_cluster_shared_dir, "ODK_ONA_cross_info");
160 my $odk_crosses = CXGN
::ODK
::Crosses
->new({
161 bcs_schema
=>$bcs_schema,
162 metadata_schema
=>$metadata_schema,
163 phenome_schema
=>$phenome_schema,
164 sp_person_id
=>$user_id,
165 sp_person_username
=>$user_name,
166 sp_person_role
=>$user_role,
167 archive_path
=>$c->config->{archive_path
},
168 temp_file_dir
=>$c->config->{basepath
}.$tempfiles_dir,
169 cross_wishlist_temp_file_path
=>$cross_wishlist_temp_file_path,
170 germplasm_info_temp_file_path
=>$germplasm_info_temp_file_path,
171 allowed_cross_properties
=>$c->config->{cross_properties
},
172 odk_crossing_data_service_url
=>$c->config->{odk_crossing_data_service_url
},
173 odk_crossing_data_service_username
=>$c->config->{odk_crossing_data_service_username
},
174 odk_crossing_data_service_password
=>$c->config->{odk_crossing_data_service_password
},
175 odk_crossing_data_service_form_id
=>$form_id,
176 odk_cross_progress_tree_file_dir
=>$progress_tree_dir
179 my $odk_crossing_data_service_name = $c->config->{odk_crossing_data_service_name
};
180 if ($odk_crossing_data_service_name eq 'ONA'){
181 my $result = $odk_crosses->save_ona_cross_info($c);
182 if ($result->{error
}){
183 $c->stash->{rest
} = { error
=> $result->{error
} };
185 } elsif ($result->{success
}){
186 $c->stash->{rest
} = { success
=> 1 };
190 $c->stash->{rest
} = { error
=> 'Error: We only support ONA as an ODK crossing service for now.' };
195 sub schedule_get_crossing_data
: Path
('/ajax/odk/schedule_get_crossing_data') : ActionClass
('REST') { }
197 sub schedule_get_crossing_data_GET
{
198 my ( $self, $c ) = @_;
199 if ($c->config->{production_server
}){
200 $c->stash->{rest
} = { error
=>'Please use contact form. Currently this cannot be set through the website.' };
203 my $form_id = $c->req->param('form_id');
204 my $timing_select = $c->req->param('timing');
205 my $session_id = $c->req->param("sgn_session_id");
210 my $dbh = $c->dbc->dbh;
211 my @user_info = CXGN
::Login
->new($dbh)->query_from_cookie($session_id);
213 $c->stash->{rest
} = {error
=>'You must be logged in to schedule ODK crossing data import!'};
216 $user_id = $user_info[0];
217 $user_role = $user_info[1];
218 my $p = CXGN
::People
::Person
->new($dbh, $user_id);
219 $user_name = $p->get_username;
222 $c->stash->{rest
} = {error
=>'You must be logged in to schedule ODK crossing data import!'};
225 $user_id = $c->user()->get_object()->get_sp_person_id();
226 $user_name = $c->user()->get_object()->get_username();
227 $user_role = $c->user->get_object->get_user_type();
229 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $user_id);
230 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $user_id);
231 my $tempfiles_dir = $c->tempfiles_subdir('ODK_ONA_cross_info');
232 my ($temp_file, $uri1) = $c->tempfile( TEMPLATE
=> 'ODK_ONA_cross_info/ODK_ONA_cross_info_downloadXXXXX');
233 my $temp_file_path = $temp_file->filename;
234 my ($cross_wishlist_temp_file, $cross_wishlist_uri1) = $c->tempfile( TEMPLATE
=> 'ODK_ONA_cross_info/ODK_ONA_cross_wishlist_downloadXXXXX');
235 my $cross_wishlist_temp_file_path = $cross_wishlist_temp_file->filename;
236 my ($germplasm_info_temp_file, $germplasm_info_uri1) = $c->tempfile( TEMPLATE
=> 'ODK_ONA_cross_info/ODK_ONA_germplasm_info_downloadXXXXX');
237 my $germplasm_info_temp_file_path = $germplasm_info_temp_file->filename;
239 my $progress_tree_dir = catdir
($c->site_cluster_shared_dir, "ODK_ONA_cross_info");
241 my $cross_properties = $c->config->{cross_properties
};
242 my $rootpath = $c->config->{rootpath
};
243 my $basepath = $c->config->{basepath
};
244 my $archive_path = $c->config->{archive_path
};
245 my $ODK_url = $c->config->{odk_crossing_data_service_url
};
246 my $ODk_username = $c->config->{odk_crossing_data_service_username
};
247 my $ODK_password = $c->config->{odk_crossing_data_service_password
};
248 my $database_name = $c->config->{dbname
};
249 my $database_user = $c->config->{dbuser
};
250 my $database_pass = $c->config->{dbpass
};
251 my $database_host = $c->config->{dbhost
};
252 my $www_user = $c->config->{www_user
};
253 my $crontab_log = $c->config->{crontab_log_filepath
};
254 my $include_path = 'export PERL5LIB="$PERL5LIB:'.$basepath.'/lib:'.$rootpath.'/cxgn-corelibs/lib:'.$rootpath.'/Phenome/lib:'.$rootpath.'/local-lib/lib/perl5"';
255 my $perl_command = "$include_path; perl $basepath/bin/ODK/ODK_ONA_get_crosses.pl -u $user_id -i $user_name -r $user_role -a $archive_path -d $basepath.$tempfiles_dir -t $temp_file_path -n $ODk_username -m $ODK_password -o $form_id -q $cross_wishlist_temp_file_path -y $germplasm_info_temp_file_path -f $progress_tree_dir -l $ODK_url -c $cross_properties -D $database_name -U $database_user -p $database_pass -H $database_host >> $crontab_log 2>&1";
257 if ($timing_select eq 'everyminute'){
258 $timing = "0-59/1 * * * * ";
259 } elsif ($timing_select eq 'everyday'){
260 $timing = "1 0 * * * ";
261 } elsif ($timing_select eq 'everyhour'){
262 $timing = "0 * * * * ";
263 } elsif ($timing_select eq 'twicedaily'){
264 $timing = "0 0,12 * * * ";
266 my $crontab_line = $timing.$perl_command."\n";
267 #print STDERR $crontab_line;
268 my $crontab_file = $c->config->{crontab_file
};
269 open (my $F, "> :encoding(UTF-8)", $crontab_file) || die "Could not open $crontab_file: $!\n";
271 print $F $crontab_line;
275 my $enable_new_crontab = "crontab -u $www_user $crontab_file";
276 system($enable_new_crontab);
278 $c->stash->{rest
} = { success
=> 1 };
283 sub get_crossing_data_cronjobs
: Path
('/ajax/odk/get_crossing_data_cronjobs') : ActionClass
('REST') { }
285 sub get_crossing_data_cronjobs_GET
{
286 my ( $self, $c ) = @_;
287 my $session_id = $c->req->param("sgn_session_id");
292 my $dbh = $c->dbc->dbh;
293 my @user_info = CXGN
::Login
->new($dbh)->query_from_cookie($session_id);
295 $c->stash->{rest
} = {error
=>'You must be logged in to see scheduled ODK crossing data import!'};
298 $user_id = $user_info[0];
299 $user_role = $user_info[1];
300 my $p = CXGN
::People
::Person
->new($dbh, $user_id);
301 $user_name = $p->get_username;
304 $c->stash->{rest
} = {error
=>'You must be logged in to see scheduled ODK crossing data import!'};
307 $user_id = $c->user()->get_object()->get_sp_person_id();
308 $user_name = $c->user()->get_object()->get_username();
309 $user_role = $c->user->get_object->get_user_type();
313 my $crontab_file = $c->config->{crontab_file
};
314 if ($crontab_file ne 'NULL') {
315 open(my $fh, '< :encoding(UTF-8)', $crontab_file)
316 or die "Could not open file '$crontab_file' $!";
318 while (my $row = <$fh>) {
320 my @c = split 'export', $row;
321 push @entries, $c[0];
326 $c->stash->{rest
} = { success
=> 1, entries
=>\
@entries };
330 sub get_crossing_available_wishlists
: Path
('/ajax/odk/get_crossing_available_wishlists') : ActionClass
('REST') { }
332 sub get_crossing_available_wishlists_GET
{
333 my ( $self, $c ) = @_;
334 my $session_id = $c->req->param("sgn_session_id");
339 my $dbh = $c->dbc->dbh;
340 my @user_info = CXGN
::Login
->new($dbh)->query_from_cookie($session_id);
342 $c->stash->{rest
} = {error
=>'You must be logged in to see ODK cross wishlists!'};
345 $user_id = $user_info[0];
346 $user_role = $user_info[1];
347 my $p = CXGN
::People
::Person
->new($dbh, $user_id);
348 $user_name = $p->get_username;
351 $c->stash->{rest
} = {error
=>'You must be logged in to see ODK cross wishlists!'};
354 $user_id = $c->user()->get_object()->get_sp_person_id();
355 $user_name = $c->user()->get_object()->get_username();
356 $user_role = $c->user->get_object->get_user_type();
358 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $user_id);
359 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $user_id);
361 my $wishlist_md_files = $metadata_schema->resultset("MdFiles")->search({filetype
=> { '-like' => 'cross_wishlist_%', }});
363 while (my $r=$wishlist_md_files->next){
364 if (index($r->filetype, 'cross_wishlist_germplasm_info_') == -1) {
365 push @wishlists, [$r->file_id, $r->filetype];
368 #print STDERR Dumper \@wishlists;
370 $c->stash->{rest
} = { success
=> 1, wishlists
=> \
@wishlists };
374 sub get_odk_cross_progress_cached
: Path
('/ajax/odk/get_odk_cross_progress_cached') : ActionClass
('REST') { }
376 sub get_odk_cross_progress_cached_GET
{
377 my ( $self, $c ) = @_;
378 my $ona_form_id = $c->req->param("form_id");
379 my $session_id = $c->req->param("sgn_session_id");
384 my $dbh = $c->dbc->dbh;
385 my @user_info = CXGN
::Login
->new($dbh)->query_from_cookie($session_id);
387 $c->stash->{rest
} = {error
=>'You must be logged in to see ODK crossing data progress!'};
390 $user_id = $user_info[0];
391 $user_role = $user_info[1];
392 my $p = CXGN
::People
::Person
->new($dbh, $user_id);
393 $user_name = $p->get_username;
396 $c->stash->{rest
} = {error
=>'You must be logged in to see ODK crossing data progress!'};
399 $user_id = $c->user()->get_object()->get_sp_person_id();
400 $user_name = $c->user()->get_object()->get_username();
401 $user_role = $c->user->get_object->get_user_type();
403 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $user_id);
404 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $user_id);
406 my $dir = catdir
($c->site_cluster_shared_dir, "ODK_ONA_cross_info");
407 eval { make_path
($dir) };
409 print "Couldn't create $dir: $@";
411 my $filename = $dir."/ona_odk_cross_progress_top_level_json_html_".$ona_form_id.".txt";
412 print STDERR
"Opening $filename \n";
414 open(my $fh, '< ":encoding(UTF-8)', $filename) or warn "cannot open file $filename";
418 $json = $line && $line ne '{}' ? decode_json
$line : {};
422 my $top_level_id = $c->req->param('id');
423 print STDERR
"ODK Cross Tree Progress Node: ".$top_level_id."\n";
424 if ($top_level_id eq '#'){
425 $top_level_id = undef;
428 $filename = $dir."/ona_odk_cross_progress_top_level_contents_html_".$ona_form_id.".txt";
429 print STDERR
"Opening $filename \n";
430 my $top_level_contents;
431 open(my $fh, '< :encoding(UTF-8)', $filename) or warn "cannot open file $filename";
435 $top_level_contents = $line && $line ne '{}' ? decode_json
$line : {};
438 $json = $top_level_contents->{$top_level_id};
441 #print STDERR Dumper $json;
442 $c->stash->{rest
} = $json;
445 sub get_odk_cross_summary_cached
: Path
('/ajax/odk/get_odk_cross_summary_cached') : ActionClass
('REST') { }
447 sub get_odk_cross_summary_cached_GET
{
448 my ( $self, $c ) = @_;
449 my $ona_form_id = $c->req->param("form_id");
450 my $session_id = $c->req->param("sgn_session_id");
455 my $dbh = $c->dbc->dbh;
456 my @user_info = CXGN
::Login
->new($dbh)->query_from_cookie($session_id);
458 $c->stash->{rest
} = {error
=>'You must be logged in to see ODK crossing data progress!'};
461 $user_id = $user_info[0];
462 $user_role = $user_info[1];
463 my $p = CXGN
::People
::Person
->new($dbh, $user_id);
464 $user_name = $p->get_username;
467 $c->stash->{rest
} = {error
=>'You must be logged in to see ODK crossing data progress!'};
470 $user_id = $c->user()->get_object()->get_sp_person_id();
471 $user_name = $c->user()->get_object()->get_username();
472 $user_role = $c->user->get_object->get_user_type();
474 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $user_id);
475 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $user_id);
477 my $dir = catdir
($c->site_cluster_shared_dir, "ODK_ONA_cross_info");
478 eval { make_path
($dir) };
480 print "Couldn't create $dir: $@";
482 my $filename = $dir."/ona_odk_cross_progress_summary_info_html_".$ona_form_id.".txt";
483 print STDERR
"Opening $filename \n";
485 open(my $fh, '< :encoding(UTF-8)', $filename) or warn "cannot open file $filename";
489 $summary = $line && $line ne '{}' ? decode_json
$line : undef;
492 $filename = $dir."/ona_odk_cross_progress_summary_plant_status_info_html_".$ona_form_id.".txt";
493 print STDERR
"Opening $filename \n";
494 my $plant_status_summary;
495 open($fh, '< :encoding(UTF-8)', $filename) or warn "cannot open file $filename";
499 $plant_status_summary = $line && $line ne '{}' ? decode_json
$line : undef;
503 #print STDERR Dumper $summary;
504 $c->stash->{rest
} = { summary
=> $summary, plant_status_summary
=> $plant_status_summary };
507 sub get_crossing_saved_ona_forms
: Path
('/ajax/odk/get_crossing_saved_ona_forms') : ActionClass
('REST') { }
509 sub get_crossing_saved_ona_forms_GET
{
510 my ( $self, $c ) = @_;
511 my $session_id = $c->req->param("sgn_session_id");
516 my $dbh = $c->dbc->dbh;
517 my @user_info = CXGN
::Login
->new($dbh)->query_from_cookie($session_id);
519 $c->stash->{rest
} = {error
=>'You must be logged in to see your saved odk ona forms!'};
522 $user_id = $user_info[0];
523 $user_role = $user_info[1];
524 my $p = CXGN
::People
::Person
->new($dbh, $user_id);
525 $user_name = $p->get_username;
528 $c->stash->{rest
} = {error
=>'You must be logged in to see your saved odk ona forms!'};
531 $user_id = $c->user()->get_object()->get_sp_person_id();
532 $user_name = $c->user()->get_object()->get_username();
533 $user_role = $c->user->get_object->get_user_type();
535 my $bcs_schema = $c->dbic_schema('Bio::Chado::Schema', 'sgn_chado', $user_id);
536 my $metadata_schema = $c->dbic_schema("CXGN::Metadata::Schema", undef, $user_id);
537 my $dbh = $bcs_schema->storage->dbh;
538 my $production_server = $c->config->{production_server
};
540 my $odk_ona_forms = _get_allowed_ONA_ODK_forms_from_lists
($dbh, $production_server);
541 $c->stash->{rest
} = {success
=> 1, odk_ona_forms
=> $odk_ona_forms};
544 sub _get_allowed_ONA_ODK_forms_from_lists
{
546 my $production_server = shift;
547 my @odk_ona_forms =();
549 if ($production_server == 1) {
550 my $odk_ona_lists = CXGN
::List
::available_public_lists
($dbh, 'odk_ona_forms');
551 my %odk_ona_forms_unique;
552 foreach (@
$odk_ona_lists) {
553 my $list = CXGN
::List
->new({ dbh
=> $dbh, list_id
=> $_->[0] });
554 my $elements = $list->elements();
555 foreach (@
$elements) {
556 $odk_ona_forms_unique{$_}++;
559 @odk_ona_forms = keys %odk_ona_forms_unique;
562 return \
@odk_ona_forms;