Merge pull request #5230 from solgenomics/topic/open_pollinated
[sgn.git] / lib / SGN / Controller / AJAX / ODK.pm
blobd8222aaa70d33f060b09afa01d33e1512aa6be9a
2 =head1 NAME
4 SGN::Controller::AJAX::ODK - a REST controller class to provide the
5 backend for ODK services
7 =head1 DESCRIPTION
9 =head1 AUTHOR
11 =cut
13 package SGN::Controller::AJAX::ODK;
15 use Moose;
16 use List::MoreUtils qw /any /;
17 use Data::Dumper;
18 use Try::Tiny;
19 use CXGN::Phenome::Schema;
20 use Bio::Chado::Schema;
21 use DateTime;
22 use SGN::Model::Cvterm;
23 use LWP::Simple;
24 use LWP::UserAgent;
25 use JSON;
26 use CXGN::ODK::Crosses;
27 use Carp;
28 use File::Spec::Functions qw / catfile catdir/;
29 use File::Path qw(make_path);
30 use CXGN::List;
32 BEGIN { extends 'Catalyst::Controller::REST' }
34 __PACKAGE__->config(
35 default => 'application/json',
36 stash_key => 'rest',
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;
58 } else {
59 print STDERR Dumper $resp;
62 } else {
63 $c->stash->{rest} = { error => 'Error: We only support SMAP as an ODK phenotyping service for now.' };
64 $c->detach();
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');
79 my $user_id;
80 my $user_name;
81 my $user_role;
82 if ($session_id){
83 my $dbh = $c->dbc->dbh;
84 my @user_info = CXGN::Login->new($dbh)->query_from_cookie($session_id);
85 if (!$user_info[0]){
86 $c->stash->{rest} = {error=>'You must be logged in to look at ONA forms!'};
87 $c->detach();
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;
93 } else{
94 if (!$c->user){
95 $c->stash->{rest} = {error=>'You must be logged in to look at ONA forms!'};
96 $c->detach();
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();
103 my $message_hash;
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");
126 my $user_id;
127 my $user_name;
128 my $user_role;
129 if ($session_id){
130 my $dbh = $c->dbc->dbh;
131 my @user_info = CXGN::Login->new($dbh)->query_from_cookie($session_id);
132 if (!$user_info[0]){
133 $c->stash->{rest} = {error=>'You must be logged in to request ODK crossing data import!'};
134 $c->detach();
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;
140 } else{
141 if (!$c->user){
142 $c->stash->{rest} = {error=>'You must be logged in to request ODK crossing data import!'};
143 $c->detach();
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} };
184 $c->detach();
185 } elsif ($result->{success}){
186 $c->stash->{rest} = { success => 1 };
187 $c->detach();
189 } else {
190 $c->stash->{rest} = { error => 'Error: We only support ONA as an ODK crossing service for now.' };
191 $c->detach();
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.' };
201 $c->detach();
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");
206 my $user_id;
207 my $user_name;
208 my $user_role;
209 if ($session_id){
210 my $dbh = $c->dbc->dbh;
211 my @user_info = CXGN::Login->new($dbh)->query_from_cookie($session_id);
212 if (!$user_info[0]){
213 $c->stash->{rest} = {error=>'You must be logged in to schedule ODK crossing data import!'};
214 $c->detach();
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;
220 } else{
221 if (!$c->user){
222 $c->stash->{rest} = {error=>'You must be logged in to schedule ODK crossing data import!'};
223 $c->detach();
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";
256 my $timing = '';
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";
270 if ($timing){
271 print $F $crontab_line;
273 close $F;
275 my $enable_new_crontab = "crontab -u $www_user $crontab_file";
276 system($enable_new_crontab);
278 $c->stash->{rest} = { success => 1 };
279 $c->detach();
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");
288 my $user_id;
289 my $user_name;
290 my $user_role;
291 if ($session_id){
292 my $dbh = $c->dbc->dbh;
293 my @user_info = CXGN::Login->new($dbh)->query_from_cookie($session_id);
294 if (!$user_info[0]){
295 $c->stash->{rest} = {error=>'You must be logged in to see scheduled ODK crossing data import!'};
296 $c->detach();
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;
302 } else{
303 if (!$c->user){
304 $c->stash->{rest} = {error=>'You must be logged in to see scheduled ODK crossing data import!'};
305 $c->detach();
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();
312 my @entries;
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>) {
319 chomp $row;
320 my @c = split 'export', $row;
321 push @entries, $c[0];
323 close $fh;
326 $c->stash->{rest} = { success => 1, entries=>\@entries };
327 $c->detach();
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");
335 my $user_id;
336 my $user_name;
337 my $user_role;
338 if ($session_id){
339 my $dbh = $c->dbc->dbh;
340 my @user_info = CXGN::Login->new($dbh)->query_from_cookie($session_id);
341 if (!$user_info[0]){
342 $c->stash->{rest} = {error=>'You must be logged in to see ODK cross wishlists!'};
343 $c->detach();
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;
349 } else{
350 if (!$c->user){
351 $c->stash->{rest} = {error=>'You must be logged in to see ODK cross wishlists!'};
352 $c->detach();
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_%', }});
362 my @wishlists;
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 };
371 $c->detach();
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");
380 my $user_id;
381 my $user_name;
382 my $user_role;
383 if ($session_id){
384 my $dbh = $c->dbc->dbh;
385 my @user_info = CXGN::Login->new($dbh)->query_from_cookie($session_id);
386 if (!$user_info[0]){
387 $c->stash->{rest} = {error=>'You must be logged in to see ODK crossing data progress!'};
388 $c->detach();
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;
394 } else{
395 if (!$c->user){
396 $c->stash->{rest} = {error=>'You must be logged in to see ODK crossing data progress!'};
397 $c->detach();
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) };
408 if ($@) {
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";
413 my $json;
414 open(my $fh, '< ":encoding(UTF-8)', $filename) or warn "cannot open file $filename";
416 local $/;
417 my $line = <$fh>;
418 $json = $line && $line ne '{}' ? decode_json $line : {};
420 close($fh);
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;
427 if ($top_level_id){
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";
433 local $/;
434 my $line = <$fh>;
435 $top_level_contents = $line && $line ne '{}' ? decode_json $line : {};
437 close($fh);
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");
451 my $user_id;
452 my $user_name;
453 my $user_role;
454 if ($session_id){
455 my $dbh = $c->dbc->dbh;
456 my @user_info = CXGN::Login->new($dbh)->query_from_cookie($session_id);
457 if (!$user_info[0]){
458 $c->stash->{rest} = {error=>'You must be logged in to see ODK crossing data progress!'};
459 $c->detach();
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;
465 } else{
466 if (!$c->user){
467 $c->stash->{rest} = {error=>'You must be logged in to see ODK crossing data progress!'};
468 $c->detach();
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) };
479 if ($@) {
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";
484 my $summary;
485 open(my $fh, '< :encoding(UTF-8)', $filename) or warn "cannot open file $filename";
487 local $/;
488 my $line = <$fh>;
489 $summary = $line && $line ne '{}' ? decode_json $line : undef;
491 close($fh);
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";
497 local $/;
498 my $line = <$fh>;
499 $plant_status_summary = $line && $line ne '{}' ? decode_json $line : undef;
501 close($fh);
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");
512 my $user_id;
513 my $user_name;
514 my $user_role;
515 if ($session_id){
516 my $dbh = $c->dbc->dbh;
517 my @user_info = CXGN::Login->new($dbh)->query_from_cookie($session_id);
518 if (!$user_info[0]){
519 $c->stash->{rest} = {error=>'You must be logged in to see your saved odk ona forms!'};
520 $c->detach();
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;
526 } else{
527 if (!$c->user){
528 $c->stash->{rest} = {error=>'You must be logged in to see your saved odk ona forms!'};
529 $c->detach();
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 {
545 my $dbh = shift;
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;