app/models/publication.rb
require 'acts_as_asset'
require 'grouped_pagination'
require 'title_trimmer'
require 'libxml'
class Publication < ActiveRecord::Base
include Seek::Rdf::RdfGeneration
title_trimmer
alias_attribute :description, :abstract
#searchable must come before acts_as_asset is called
searchable(:ignore_attribute_changes_of=>[:updated_at,:last_used_at]) do
text :journal,:pubmed_id, :doi, :published_date
text :publication_authors do
publication_authors.compact.map(&:first_name) + publication_authors.compact.map(&:last_name)
end
text :non_seek_authors do
non_seek_authors.compact.map(&:first_name) + non_seek_authors.compact.map(&:last_name)
end
end if Seek::Config.solr_enabled
acts_as_asset
def default_policy
policy = Policy.new(:name => "publication_policy", :sharing_scope => Policy::EVERYONE, :access_type => Policy::VISIBLE)
#add managers (authors + contributor)
creators.each do |author|
policy.permissions << Permissions.create(:contributor => author, :policy => policy, :access_type => Policy::MANAGING)
end
#Add contributor
c = contributor || default_contributor
policy.permissions << Permission.create(:contributor => c.person, :policy => policy, :access_type => Policy::MANAGING) if c
policy
end
validate :check_identifier_present
validate :check_uniqueness_of_identifier_within_project, :unless => "Seek::Config.is_virtualliver"
validate :check_uniqueness_of_title_within_project, :unless => "Seek::Config.is_virtualliver"
validates_uniqueness_of :pubmed_id , :allow_nil => true, :allow_blank => true, :if => "Seek::Config.is_virtualliver"
validates_uniqueness_of :doi ,:allow_nil => true, :allow_blank => true, :if => "Seek::Config.is_virtualliver"
validates_uniqueness_of :title , :if => "Seek::Config.is_virtualliver"
has_many :publication_authors, :dependent => :destroy, :autosave => true
after_update :update_creators_from_publication_authors , :if => "Seek::Config.is_virtualliver"
after_update :update_policy_from_publication_authors , :if=> "false"
def update_creators_from_publication_authors
self.creators = publication_authors.map(&:person).compact
end
def update_policy_from_publication_authors
#Update policy so current authors have manage permissions
policy.permissions.clear
creators.each do |author|
policy.permissions << Permission.create(:contributor => author, :policy => policy, :access_type => Policy::MANAGING)
end
#Add contributor
policy.permissions << Permission.create(:contributor => contributor.person, :policy => policy, :access_type => Policy::MANAGING) unless contributor.nil?
end
has_many :backwards_relationships,
:class_name => 'Relationship',
:as => :other_object,
:dependent => :destroy
if Seek::Config.events_enabled
has_and_belongs_to_many :events
else
def events
[]
end
def event_ids
[]
end
def event_ids= events_ids
end
end
alias :seek_authors :creators
scope :default_order, order("published_date DESC")
def non_seek_authors
publication_authors.find_all_by_person_id nil
end
def self.sort publications
publications.sort_by &:published_date
end
def contributor_credited?
false
end
def extract_metadata(reference)
if reference.respond_to?(:pubmed)
extract_pubmed_metadata(reference)
else
extract_doi_metadata(reference)
end
end
def extract_pubmed_metadata(reference)
self.title = reference.title.chop #remove full stop
self.abstract = reference.abstract
self.journal = reference.journal
self.pubmed_id = reference.pubmed
self.published_date = reference.published_date
self.citation = reference.citation
end
def extract_doi_metadata(doi_record)
self.title = doi_record.title
self.published_date = doi_record.date_published
self.journal = doi_record.journal
self.doi = doi_record.doi
self.publication_type = doi_record.publication_type
self.citation = doi_record.citation
end
def related_data_files
self.backwards_relationships.select {|a| a.subject_type == "DataFile"}.collect { |a| a.subject }
end
def related_models
self.backwards_relationships.select {|a| a.subject_type == "Model"}.collect { |a| a.subject }
end
def related_assays
self.backwards_relationships.select {|a| a.subject_type == "Assay"}.collect { |a| a.subject }
end
def related_presentations
self.backwards_relationships.select {|a| a.subject_type == "Presentation"}.collect { |a| a.subject }
end
#includes those related directly, or through an assay
def all_related_data_files
via_assay = related_assays.collect do |assay|
assay.data_file_masters
end.flatten.uniq.compact
via_assay | related_data_files
end
#includes those related directly, or through an assay
def all_related_models
via_assay = related_assays.collect do |assay|
assay.model_masters
end.flatten.uniq.compact
via_assay | related_models
end
#indicates whether the publication has data files or models linked to it (either directly or via an assay)
def has_assets?
#FIXME: requires a unit test
!all_related_data_files.empty? || !all_related_models.empty?
end
#returns a list of related organisms, related through either the assay or the model
def related_organisms
organisms = related_assays.collect{|a| a.organisms}.flatten.uniq.compact
organisms = organisms | related_models.collect{|m| m.organism}.uniq.compact
organisms
end
def self.subscribers_are_notified_of? action
action == 'create'
end
def endnote
bio_reference.endnote
end
def publication_author_names
author_names = []
publication_authors.each do |author|
if author.kind_of?(Person)
author_names << author.name
else
author_names << author.first_name + " " + author.last_name
end
end
author_names
end
private
def bio_reference
if pubmed_id
Bio::MEDLINE.new(Bio::PubMed.efetch(pubmed_id).first).reference
else
#TODO: Bio::Reference supports a 'url' option. Should this be the URL on seek, or the URL of the 'View Publication' button, or neither?
Bio::Reference.new({:title => title, :journal => journal, :abstract => abstract,
:authors => publication_authors.map {|e| e.person ? [e.person.last_name, e.person.first_name].join(', ') : [e.last_name, e.first_name].join(', ')},
:year => published_date.year}.with_indifferent_access)
end
end
def check_identifier_present
if doi.blank? && pubmed_id.blank?
self.errors[:base] << "Please specify either a PubMed ID or DOI"
return false
end
if !doi.blank? && !pubmed_id.blank?
self.errors[:base] << "Can't have both a PubMed ID and a DOI"
return false
end
true
end
def check_uniqueness_of_identifier_within_project
if !doi.blank?
existing = Publication.find_all_by_doi(doi) - [self]
if !existing.empty?
matching_projects = existing.collect(&:projects).flatten.uniq & projects
if !matching_projects.empty?
self.errors[:base] << "You cannot register the same DOI within the same project"
return false
end
end
end
if !pubmed_id.blank?
existing = Publication.find_all_by_pubmed_id(pubmed_id) - [self]
if !existing.empty?
matching_projects = existing.collect(&:projects).flatten.uniq & projects
if !matching_projects.empty?
self.errors[:base] << "You cannot register the same PubMed ID within the same project"
return false
end
end
end
true
end
def check_uniqueness_of_title_within_project
existing = Publication.find_all_by_title(title) - [self]
if !existing.empty?
matching_projects = existing.collect(&:projects).flatten.uniq & projects
if !matching_projects.empty?
self.errors[:base] << "You cannot register the same Title within the same project"
return false
end
end
end
#defines that this is a user_creatable object type, and appears in the "New Object" gadget
def self.user_creatable?
true
end
end