1 package CXGN
::Chado
::PublicationDetailPage
;
3 use base qw
/CXGN::Page::Form::SimpleFormPage/;
9 use CXGN
::Page
::FormattingHelpers qw
/info_section_html
16 use CXGN
::People
::Person
;
17 use CXGN
::Chado
::Publication
;
18 use CXGN
::Chado
::Pubauthor
;
19 use CXGN
::Phenome
::Locus
;
20 use CXGN
::Phenome
::Locus
::LocusRanking
;
21 use CXGN
::Phenome
::Allele
;
22 use CXGN
::Chado
::Dbxref
;
24 use CXGN
::People
::PageComment
;
25 use CXGN
::Tools
::Text qw
/ sanitize_string /;
27 my $publication_detail_page=CXGN
::Chado
::PublicationDetailPage
->new();
31 my $self= $class->SUPER::new
(@_);
32 $self->set_script_name("publication.pl");
39 $self->set_dbh(CXGN
::DB
::Connection
->new() );
40 my %args= $self->get_args();
41 foreach my $k (keys %args) {
42 $args{$k} = sanitize_string
($args{$k});
44 my $pub_id= $args{pub_id
};
46 unless (!$pub_id || $pub_id =~m
/^\d+$/) { $self->get_page->message_page("No publication exists for identifier: $pub_id"); }
47 $self->set_object_id($pub_id);
48 $self->set_object(CXGN
::Chado
::Publication
->new($self->get_dbh, $self->get_object_id));
50 $self->set_primary_key("pub_id");
57 my %args = $self->get_args();
58 my $publication=$self->get_object();
59 my $pub_id = $self->get_object_id();
60 my $pub_title = $publication->get_title();
61 my $page="/chado/publication.pl?pub_id=?";
62 my $action= $args{action
} || "";
64 #import javascript libraries
65 $self->get_page()->jsan_use("jquery");
66 $self->get_page()->jsan_use("CXGN.Phenome.Locus");
67 $self->get_page()->jsan_use("CXGN.Phenome.Publication");
69 if (!$pub_title && $action ne 'new' && $action ne 'store') { $self->get_page->message_page("No publication exists for this identifier");}
72 $self->get_page->header("SGN publication $pub_title");
73 print page_title_html
("Publication:\t$pub_title\n");
75 my $edit_links=$self->get_edit_links();
77 my $pub_html=$edit_links. "<br />". $self->get_form->as_table_string(). "<br />";
78 if ($action eq 'new') { print qq |<p
><b
><a href
= "/chado/add_publication.pl?action=new&type=$args{type}&type_id=$args{type_id}&reffering_page=$args{reffering_page}">Store PubMed publication
.</a></b
></p
>|; }
79 print info_section_html
(title
=> 'Publication details',
80 contents
=> $pub_html ,
82 if ($args{refering_page
}) { print qq |<a href
="$args{refering_page}">Go back to refering page
.</a><br />|; }
84 my $dbxref_html=$self->get_dbxref_html($publication->get_dbxrefs());
86 print info_section_html
(title
=> 'External resources',
87 contents
=> $dbxref_html ,
90 my @loci= $publication->get_loci();
91 foreach my $locus(@loci) {
92 my $locus_id = $locus->get_locus_id();
93 my $locus_symbol= $locus->get_locus_symbol();
94 my $cname=$locus->get_common_name();
95 $loci_link .= qq|<a href
="/phenome/locus_display.pl?locus_id=$locus_id">$cname '$locus_symbol'</a><br />| if $locus->get_obsolete() eq 'f';
97 print info_section_html
(title
=> 'Associated loci',
98 contents
=> $loci_link ,
100 my $user_type= $self->get_user()->get_user_type();
101 if ($args{get_ranked_loci
} && $user_type eq 'curator' ) { $self->rank_loci_now(); }
103 my $ranked_loci= $self->get_ranked_loci();
104 print info_section_html
(title
=> 'Matched loci',
105 contents
=> $ranked_loci ,
110 if ($user_type eq 'curator') {
111 # the text-indexing function does not do the right thing now
112 # have to modify it so the search will be against just the current publication
113 print info_section_html
(title
=> 'Curator Tools',
114 contents
=> $self->get_curator_tools(),
118 my $page_comment_obj = CXGN
::People
::PageComment
->new($self->get_dbh(), "pub", $pub_id, $self->get_page()->{request
}->uri()."?".$self->get_page()->{request
}->args());
119 print $page_comment_obj->get_html();
121 $self->get_page()->footer();
128 my $publication = $self->get_object();
129 my $sp_person_id=$self->get_user()->get_sp_person_id();
131 my %args = $self->get_args();
133 my $action=$args{action
};
134 my $refering_page=$args{refering_page
};
135 my $type= $args{type
}; #locus or allele or stock or...?
136 my $type_id = $args{type_id
}; #the database id of the refering object (locus..)
137 my $script_name= $self->get_script_name();
138 my $db_name= "SGN_ref";
140 #db_name, accession, and uniquename will not be changed when updating..
141 if (!$publication->get_db_name()) { $publication->set_db_name($db_name); }
143 $publication->set_cvterm_name('journal'); #this should be implemented in the form framework- maybe a drop down list with publication types from cvterm table??
146 $self->SUPER::store
(1);
148 my @dbxrefs=$publication->get_dbxrefs();
149 foreach my $dbxref(@dbxrefs) {
150 my ($locus, $allele);
151 if ($type eq 'locus') {
152 $locus= CXGN
::Phenome
::Locus
->new($self->get_dbh(), $type_id);
153 $locus->add_locus_dbxref($dbxref, undef, $sp_person_id);
155 elsif ($type eq 'allele') {
156 $allele= CXGN
::Phenome
::Allele
->new($self->get_dbh(), $type_id);
157 $allele->add_allele_dbxref($dbxref, undef, $sp_person_id);
160 my $pub_id= $publication->get_pub_id();
161 if ($type eq 'stock' ) {
162 my $pub = $publication->bcs_pub;
163 $pub->find_or_create_related('stock_pubs', {
167 if ($refering_page) {
168 $self->get_page()->client_redirect("/chado/add_publication.pl?type=$type&type_id=$type_id&refering_page=$refering_page&action=new");
170 $self->get_page()->client_redirect("/chado/publication.pl?pub_id=$pub_id");
177 my $publication=$self->get_object();
179 my %args=$self->get_args();
180 my $type = $args{type
};
181 my $type_id = $args{type_id
};
182 my $refering_page= $args{refering_page
};
184 my $author_example = tooltipped_text
('Authors', 'Author names should be entered in the order of last name, followed by "," then first name followed by ".". e.g Darwin, Charles. van Rijn, Henk. Giorgio,AB');
186 $self->get_form()->add_textarea(
187 display_name
=> "Title",
188 field_name
=> "title",
189 object
=> $publication,
190 getter
=> "get_title",
191 setter
=> "set_title",
197 $self->get_form()->add_field(
198 display_name
=> "Series name",
199 field_name
=> "series_name",
200 object
=> $publication,
201 getter
=> "get_series_name",
202 setter
=> "set_series_name",
205 $self->get_form()->add_field(
206 display_name
=> "Volume",
207 field_name
=> "volume",
208 object
=> $publication,
209 getter
=> "get_volume",
210 setter
=> "set_volume",
213 $self->get_form()->add_field(
214 display_name
=> "Issue",
215 field_name
=> "issue",
216 object
=> $publication,
217 getter
=> "get_issue",
218 setter
=> "set_issue",
221 $self->get_form()->add_field (
222 display_name
=> "Year",
223 field_name
=> "pyear",
224 object
=> $publication,
225 getter
=> "get_pyear",
226 setter
=> "set_pyear",
227 validate
=> 'integer',
229 $self->get_form()->add_field (
230 display_name
=> "Pages",
231 field_name
=> "pages",
232 object
=> $publication,
233 getter
=> "get_pages",
234 setter
=> "set_pages",
235 validate
=> 'string',
237 $self->get_form()->add_textarea (
238 display_name
=> $author_example,
239 field_name
=> "author",
240 object
=> $publication,
241 getter
=> "get_authors_as_string",
242 setter
=> "set_author_string",
246 $self->get_form()->add_textarea (
247 display_name
=> "Abstract",
248 field_name
=> "abstract",
249 object
=> $publication,
250 getter
=> "get_abstract",
251 setter
=> "set_abstract",
255 $self->get_form()->add_hidden (
256 field_name
=> "pub_id",
257 contents
=>$args{pub_id
},
258 object
=> $publication,
259 getter
=> "get_pub_id",
260 setter
=> "set_pub_id",
263 $self->get_form()->add_hidden (
264 field_name
=> "type",
267 $self->get_form()->add_hidden (
268 field_name
=> "type_id",
271 $self->get_form()->add_hidden(
272 field_name
=>"refering_page",
273 contents
=>$refering_page,
275 $self->get_form()->add_hidden( field_name
=>"action", contents
=>"store" );
277 if ($self->get_action=~ /view|edit/) {
278 $self->get_form->from_database();
280 elsif ($self->get_action=~ /store/) {
281 $self->get_form->from_request($self->get_args());
282 $self->send_publication_email('store');
288 my %args = $self->get_args();
289 $self->check_modify_privileges();
290 my $publication=$self->get_object();
292 my $pub_id = $publication->get_pub_id();
294 $pub_title = $publication->get_title();
295 my $message = $publication->delete();
297 $self->send_publication_email('delete');
298 }else { $self->get_page()->message_page($message) ; }
300 $self->get_page()->message_page("Deleted publication $pub_id ($pub_title) from database");
304 #overriding to allow access only to curators
305 sub check_modify_privileges
{
307 # implement quite strict access controls by default
309 my $person_id = $self->get_login()->verify_session();
310 my $user = CXGN
::People
::Person
->new($self->get_dbh(), $person_id);
311 my $user_id = $user->get_sp_person_id();
312 if ($user->get_user_type() eq 'curator' || $user->get_user_type() eq 'submitter' || $user->get_user_type eq 'sequencer') {
315 $self->get_page()->message_page("This page is only available for SGN curators!!");
319 sub get_dbxref_html
{
323 foreach my $d(@dbxrefs) {
324 my $db=$d->get_db_name();
325 if ($db ne 'SGN_ref') {
326 my $url = $d->get_urlprefix() . $d->get_url() . $d->get_accession();
327 $html .= qq| <a href
= "$url" >| . "$db:" . $d->get_accession() . "</a>";
333 sub get_ranked_loci
{
335 my $pub=$self->get_object();
336 my $loci_hash=$pub->get_ranked_loci();
338 my ($val_pubs, $rej_pubs, $pending_pubs, $a_pubs)= ("" x
4);
341 my $user_type= $self->get_user()->get_user_type();
343 foreach(sort { $loci_hash->{$b} <=> $loci_hash->{$a} } keys %$loci_hash ) {
344 my $locus=CXGN
::Phenome
::Locus
->new($self->get_dbh, $_);
345 my $locus_symbol= $locus->get_locus_symbol();
346 my $locus_name= $locus->get_locus_name();
347 my $common_name= $locus->get_common_name();
348 my $pub_id = $pub->get_pub_id();
349 my $dbxref_id = $pub->get_dbxref_id_by_db('PMID');
351 my $locusRank = CXGN
::Phenome
::Locus
::LocusRanking
->new($self->get_dbh(), $_, $pub_id);
352 my $validated = $locusRank->get_validate() || "";
353 my $score = $locusRank->get_rank();
355 my $val_form= "<BR><BR>";
356 if ($user_type eq 'curator') {
358 <div id
='locusPubForm_$pub_id'>
359 <div id
='pub_dbxref_id_$dbxref_id'>
362 id
="dbxref_id_$pub_id">
363 <select id
="$dbxref_id" >
364 <option value
="" selected
></option
>
365 <option value
="no">no</option
>
366 <option value
="yes">yes
</option
>
367 <option value
="maybe">maybe
</option
>
370 id
="associate_pub_button"
371 value
="Validate match"
372 onclick
="Locus.addLocusDbxref('$_', '$dbxref_id');this.disabled=false;">
378 my $associated= $pub->is_associated_publication('locus', $_);
380 if ($validated) { $val_string = "(validated: $validated)"; }
381 $locus_link .= qq| <a href
="/phenome/locus_display.pl?locus_id=$_">$locus_symbol.</a> $common_name '$locus_name' <b> Match score = $score </b
> $val_string | . $val_form;
388 sub send_publication_email
{
390 my %args= $self->get_args();
391 my $refering_page=$args{refering_page
};
392 my $type= $args{type
}; #locus or allele or stock or...?
393 my $type_id = $args{type_id
}; #the database id of the refering object (locus..)
394 my $accession= $args{accession
};
396 my $action= $self->get_action();
397 my $username= $self->get_user()->get_first_name()." ".$self->get_user()->get_last_name();
398 my $sp_person_id=$self->get_user()->get_sp_person_id();
400 my $user_link = qq | /solpeople/personal
-info
.pl?sp_person_id
=$sp_person_id|;
402 my $usermail=$self->get_user()->get_contact_email();
406 if ($action eq 'store') {
407 $subject="[New non PubMed publication associated with $type: $type_id]";
408 $fdbk_body="$username($user_link) has associated a non pubmed publication $accession with $type : $type_id";
410 elsif($action eq 'delete') {
411 $subject="[A publication-locus association removed from $type : $type_id]";
412 $fdbk_body="$username ($user_link) has removed a publication from $type : $type_id ";
414 CXGN
::Contact
::send_email
($subject,$fdbk_body, 'sgn-db-curation@sgn.cornell.edu');
420 my $form_name = shift;
421 return $self->get_new_link_html($form_name)." ".
422 $self->get_edit_link_html($form_name) ." ". $self->get_delete_link_html($form_name);
426 sub get_edit_link_html
{
428 my $form_name = shift;
430 my $script_name = $self->get_script_name();
431 my $primary_key = $self->get_primary_key();
432 my $object_id = $self->get_object_id();
434 my $user_id= $self->get_user()->get_sp_person_id();
435 if (($self->get_user()->get_user_type() eq "curator") || ($self->get_user()->get_user_type() eq "submitter") || ( $self->get_user()->get_user_type() eq "sequencer") ) {
436 $edit_link = qq { <a href
="$script_name?action=edit&form=$form_name&$primary_key=$object_id">[Edit
]</a
> };
439 $edit_link = qq { <span
class="ghosted">[Edit
]</span
> };
441 if ($self->get_action() eq "edit") {
442 $edit_link = qq { <a href
="$script_name?action=view&form=$form_name&$primary_key=$object_id">[Cancel Edit
]</a
> };
444 if ($self->get_action() eq "new") {
445 $edit_link = qq { <span
class="ghosted">[Edit
]</span
> };
450 sub get_delete_link_html
{
452 my $form_name = shift;
453 my $delete_link = "";
454 my $script_name = $self->get_script_name();
455 my $primary_key = $self->get_primary_key();
456 my $object_id = $self->get_object_id();
457 my $user_id= $self->get_user()->get_sp_person_id();
458 if (($self->get_user()->get_user_type() eq "curator") || ($self->get_user()->get_user_type() eq "submitter") || ( $self->get_user()->get_user_type() eq "sequencer") ) {
459 $delete_link = qq { <a href
="$script_name?action=confirm_delete&form=$form_name&$primary_key=$object_id">[Delete
]</a
> };
461 $delete_link = qq { <span
class="ghosted">[Delete
]</span
> };
463 if ($self->get_action() eq "edit") {
464 $delete_link = qq { <span
class="ghosted">[Delete
]</span
> };
466 if ($self->get_action() eq "new") {
467 $delete_link = qq { <span
class="ghosted">[Delete
]</span
> };
474 sub get_curator_tools
{
476 my $pub_id= $self->get_object_id();
479 #add AJAX form for validating publication status. Current status is selected by default
480 my $stat=$self->get_object()->get_status();
481 my @stat_options= ("curated","pending", "irrelevant", "no gene");
482 my $stat_options= qq|<option value
=""></option
>|;
483 foreach my $s(@stat_options) {
484 my $selected = qq|selected
="selected"| if $s eq $stat || undef;
485 $stat_options .= qq|<option value
="$s" $selected >$s</option
>|
487 my $stats= qq|<select id
="pub_stat" onchange
="Publication.updatePubCuratorStat(this.value, $pub_id)">
491 #add AJAX form for assigning curator. Assigned curator is selected by default
492 my $assigned_to_id= $self->get_object()->get_curator_id();
493 my @curators= CXGN
::People
::Person
::get_curators
($self->get_dbh());
494 my %names = map {$_ => CXGN
::People
::Person
->new($self->get_dbh(), $_)->get_first_name() } @curators;
495 my $curator_options=qq|<option value
=""></option
>|;
496 for my $curator_id (keys %names) {
497 my $curator= $names{$curator_id};
498 my $selected = qq|selected
="selected"| if $curator_id==$assigned_to_id || undef;
499 $curator_options .=qq|<option value
="$curator_id" $selected>$curator</option
>|;
501 my $curators=qq|<select id
="pub_curator_select" onchange
="Publication.updatePubCuratorAssigned(this.value, $pub_id)">
508 <form action
="" method
="get">
509 <input id
="" type
="hidden" value
="1" name
="get_ranked_loci"/>
510 <input id
="" type
="hidden" value
="$pub_id" name
="pub_id"/>
512 <input type
="submit" value
="Get ranked loci"/>
517 Publications are automatically indexed when inserted into the database. A nightly cron job connects publications with loci based on text matching. You may run the matching algorithm manually to see now the possible matching loci. This might take a few minutes to load. After clicking this link the page will automatically reload. If matching loci are found these will be printed in the 'Matched loci' section above.
522 my $search = qq|Go back to
<a href
="/search/pub_search.pl">literature search page
</a
>.|;
523 return info_table_html
('Publication status'=>$stats,
524 'Assigned to curator'=> $curators ,
525 'Text index'=> $html)
532 my $pub=$self->get_object();
533 my $pub_id= $self->get_object_id();
534 my $title_string= $pub->title_tsvector_string();
535 $title_string =~ s/\'//g;
537 print STDERR
"title_string = $title_string ! \n";
538 my @match_words = split (/\s/, $title_string);
539 #print STDERR "match_words= @match_words\n";
540 my $abstract_string= $pub->abstract_tsvector_string();
541 $abstract_string =~ s/\'//g;
542 push (@match_words, (split /\s/, $abstract_string) );
544 #hash for storing unique loci.
546 MATCH
: foreach (@match_words) {
548 print STDERR
"...matching $_ ...\n";
549 my $get_loci_q= ("SELECT distinct locus_id FROM phenome.locus WHERE locus_name SIMILAR TO ?
550 OR locus_symbol SIMILAR TO ? OR gene_activity SIMILAR TO ? OR description SIMILAR TO ?
552 my $l_sth=$self->get_dbh()->prepare($get_loci_q);
553 $l_sth->execute($_, $_, $_, $_);
554 my (@loci)=$l_sth->fetchrow_array();
556 ##limiting the number of hits to 20 to keep this function from extremely slowing down the page.
557 if (scalar(@loci) > 20 ) { print STDERR
" Found ". scalar(@loci) . "loci! skipping...\n"; next MATCH
; }
558 else { foreach(@loci) { $loci_subset{$_}++; } }
560 foreach my $locus_id (sort {$loci_subset{$a} <=> $loci_subset{$b} } keys %loci_subset) {
561 my $locus = CXGN
::Phenome
::Locus
->new($self->get_dbh(), $locus_id);
563 my %pub= $locus->add_locus_pub_rank($pub_id);
564 #while ( my ($match_type, $value) = each(%pub) ) {
565 # print STDERR ("$match_type=> $value\n");