To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / plugins / redmine_bibliography / app / models @ 1584:8b1dc5e31dbc

1 328:aed18b463206 luis
class Author < ActiveRecord::Base
2 946:a0c9cc95bcf3 luis
  unloadable
3 1123:48c5fdd6cf10 luis
4 468:0bb9c7baed07 luis
  has_many :authorships, :dependent => :destroy
5 328:aed18b463206 luis
  has_many :publications, :through => :authorships
6 403:b15397a5341c luis
7 466:a7dc708d48a1 luis
  belongs_to :user
8 478:7097dc91e58e luis
9
  def <=>(author)
10
    name.downcase <=> author.name.downcase
11
  end
12 1123:48c5fdd6cf10 luis
13 1124:807426fa6017 luis
  # todo: review usage of scope --lf.20130108
14 1123:48c5fdd6cf10 luis
  scope :like, lambda {|q|
15 477:aeedcec4df5f luis
    s = "%#{q.to_s.strip.downcase}%"
16
    {:conditions => ["LOWER(name) LIKE :s", {:s => s}],
17
     :order => 'name'
18
    }
19 478:7097dc91e58e luis
  }
20
21 1412:48d9b3ae9e1a luis
  def institution
22 1413:0e40e05048eb luis
    if self.authorships.first.nil?
23
      ""
24
    else
25
      self.authorships.first.institution
26
    end
27 1412:48d9b3ae9e1a luis
  end
28 1414:07444815c0bd luis
29
  def mail
30
    if self.authorships.first.nil?
31
      ""
32
    else
33
      self.authorships.first.mail
34
    end
35
  end
36
37 1420:b688fe79f593 luis
  # todo: need to fix the name getter
38 1417:1df2db7f0e4d luis
  def name
39 1420:b688fe79f593 luis
    if self.authorships.first.nil?
40
      ""
41
    else
42
      self.authorships.first.name
43 1417:1df2db7f0e4d luis
    end
44
  end
45
46 328:aed18b463206 luis
end
47
class Authorship < ActiveRecord::Base
48 1123:48c5fdd6cf10 luis
  unloadable
49
50 328:aed18b463206 luis
  belongs_to :author
51
  belongs_to :publication
52 1123:48c5fdd6cf10 luis
53 483:cc267eb99115 luis
  accepts_nested_attributes_for :author
54
  accepts_nested_attributes_for :publication
55 686:b1debf464389 luis
56
  validates_presence_of :name_on_paper
57 1123:48c5fdd6cf10 luis
58 1395:0e4c6c2f400e luis
  attr_writer :search_author_id , :search_author_class
59 1394:0f918e37e1d6 luis
  attr_writer :search_author_tie
60 1364:4d5d25039a5f luis
61 1394:0f918e37e1d6 luis
  ### attr_accessor :search_results, :identify_author
62
  ## attr_writer :search_author_class
63
64 1395:0e4c6c2f400e luis
  before_save :set_author
65 1367:a2e51c0a7860 luis
  before_update :delete_publication_cache
66 591:9e866f13c984 luis
67 1363:855b4ae5ecdd luis
  # tod: review scope of ordering
68
  acts_as_list :column => 'auth_order'
69 1317:2805873c0147 luis
70 1124:807426fa6017 luis
  # todo: review usage of scope --lf.20130108
71 1123:48c5fdd6cf10 luis
  scope :like_unique, lambda {|q|
72 601:1608b3cb50cd luis
    s = "%#{q.to_s.strip.downcase}%"
73
    {:conditions => ["LOWER(name_on_paper) LIKE :s OR LOWER(email) LIKE :s", {:s => s}],
74
     :order => 'name_on_paper',
75
     :group => "name_on_paper, institution, email"
76
    }
77
  }
78
79 1124:807426fa6017 luis
  # todo: review usage of scope --lf.20130108
80 1123:48c5fdd6cf10 luis
  scope :like, lambda {|q|
81 591:9e866f13c984 luis
    s = "%#{q.to_s.strip.downcase}%"
82 601:1608b3cb50cd luis
    {:conditions => ["LOWER(name_on_paper) LIKE :s OR LOWER(email) LIKE :s", {:s => s}],
83 591:9e866f13c984 luis
     :order => 'name_on_paper'
84
    }
85
  }
86 1123:48c5fdd6cf10 luis
87 1394:0f918e37e1d6 luis
  def search_author_class
88
    # Authorship must always have an Author
89
    # unless it hasn't been saved yet
90
    # using default setter (attr_writer)
91
92
    if self.author.nil?
93 1397:bf2db886a543 luis
      aclass = ""
94 1394:0f918e37e1d6 luis
    else
95 1397:bf2db886a543 luis
      aclass = "Author"
96 1394:0f918e37e1d6 luis
    end
97 1395:0e4c6c2f400e luis
98 1397:bf2db886a543 luis
    @search_author_class || aclass
99 1394:0f918e37e1d6 luis
  end
100
101
  def search_author_id
102
    if self.author.nil?
103 1398:92d854be33d5 luis
      authid = ""
104 1394:0f918e37e1d6 luis
    else
105 1397:bf2db886a543 luis
      authid = author_id
106 1394:0f918e37e1d6 luis
    end
107 1397:bf2db886a543 luis
108
    @search_author_id || authid
109 1394:0f918e37e1d6 luis
  end
110
111
  def search_author_tie
112
    if self.author.nil?
113 1397:bf2db886a543 luis
      auth_tie = false
114 1394:0f918e37e1d6 luis
    else
115 1397:bf2db886a543 luis
      auth_tie = true
116 1394:0f918e37e1d6 luis
    end
117
118 1397:bf2db886a543 luis
    @search_author_tie || auth_tie
119 1394:0f918e37e1d6 luis
  end
120
121 592:68c6b060385c luis
  def name
122
    return self.name_on_paper
123
  end
124 1123:48c5fdd6cf10 luis
125 591:9e866f13c984 luis
  def <=>(authorship)
126 592:68c6b060385c luis
    name.downcase <=> authorship.name.downcase
127
  end
128 1123:48c5fdd6cf10 luis
129 592:68c6b060385c luis
  def mail
130
    return self.email
131 591:9e866f13c984 luis
  end
132 1123:48c5fdd6cf10 luis
133
  protected
134 1367:a2e51c0a7860 luis
135
  def delete_publication_cache
136
    publication = Publication.find(self.publication_id)
137
    Rails.cache.delete "publication-#{publication.id}-ieee"
138
    Rails.cache.delete "publication-#{publication.id}-bibtex"
139
  end
140
141 1395:0e4c6c2f400e luis
  private
142
143 1394:0f918e37e1d6 luis
  def set_author
144 1403:35732ac4324a luis
    # do we want to associate the authorship
145
    #  with an existing author/user?
146
    if @search_author_tie
147
      # if an author, simply associates with it
148
      # if an user, checks if it has already an author associated with it
149
      #   if so, associates with that author
150
      #   otherwise, creates a new author
151 1394:0f918e37e1d6 luis
152 1403:35732ac4324a luis
      case @search_author_class
153
      when ""
154
        author = Author.new
155
        author.save
156 1394:0f918e37e1d6 luis
157 1403:35732ac4324a luis
      when "User"
158
        user = User.find(@search_author_id)
159 1394:0f918e37e1d6 luis
160 1403:35732ac4324a luis
        if user.author.nil?
161
          # User w/o author:
162
          # create new author and update user
163
          author = Author.new
164
          author.save
165
          user.author = author
166
          user.save
167
        else
168
          author = user.author
169
        end
170
171
      when "Author"
172
        author = Author.find(@search_author_id)
173
      end
174
175
    # if we don't want to associate with an existing author/user
176
    else
177
      # todo: should we delete any previously existing relationship?
178 1366:7e85f7988ab8 luis
      author = Author.new
179
      author.save
180 1394:0f918e37e1d6 luis
    end
181 1366:7e85f7988ab8 luis
182 1394:0f918e37e1d6 luis
    self.author = author
183 518:b24091590b63 luis
  end
184 328:aed18b463206 luis
end
185 393:9595ab4cac6b luis
class BibtexEntry < ActiveRecord::Base
186 544:f05f3a9ef569 luis
  unloadable
187
188 393:9595ab4cac6b luis
  belongs_to :publication
189 544:f05f3a9ef569 luis
  validates_presence_of :entry_type
190
191
  def entry_type_name
192
    entry_type = self.entry_type
193
    BibtexEntryType.find(entry_type).name
194
  end
195
196 586:658cfb481618 chris
  def entry_type_label
197
    entry_type = self.entry_type
198
    BibtexEntryType.find(entry_type).label
199 685:4481db876cdb luis
  end
200 393:9595ab4cac6b luis
end
201 542:23a9272bf766 luis
class BibtexEntryType < ActiveRecord::Base
202 946:a0c9cc95bcf3 luis
  unloadable
203 685:4481db876cdb luis
204 1394:0f918e37e1d6 luis
  @@fields = Hash['article', ['journal', 'year', 'volume', 'number', 'pages', 'month', 'note' ],
205 685:4481db876cdb luis
                  'book' , [ 'editor', 'publisher', 'volume', 'series', 'address', 'edition', 'month', 'year', 'note' ],
206
                  'booklet' , [ 'howpublished', 'address', 'year', 'month', 'note', 'key' ],
207
                  'conference', [ 'booktitle', 'year', 'editor', 'pages', 'organization', 'publisher', 'address', 'month', 'note' ],
208
                  'inbook', [ 'editor', 'publisher', 'chapter', 'pages', 'volume', 'series', 'address', 'edition', 'year', 'note' ],
209
                  'incollection', [ 'editor', 'publisher', 'chapter', 'pages', 'volume', 'series', 'address', 'edition', 'year', 'note' ],
210
                  'inproceedings', [ 'booktitle', 'year', 'editor', 'pages', 'organization', 'publisher', 'address', 'month', 'note' ],
211
                  'manual', [ 'organization', 'address', 'edition', 'month', 'year', 'note' ],
212
                  'masterthesis', [ 'school', 'year', 'address', 'month', 'note' ],
213
                  'misc', [ 'howpublished', 'month', 'year', 'note' ],
214
                  'phdthesis', [ 'school', 'year', 'address', 'month', 'note' ],
215
                  'proceedings', [ 'booktitle', 'year', 'editor', 'pages', 'organization', 'publisher', 'address', 'month', 'note' ],
216
                  'techreport', [ 'year', 'type', 'number', 'address', 'month', 'note' ],
217
                  'unpublished', [ 'note', 'month', 'year' ]]
218
219 586:658cfb481618 chris
  def redundant?
220
    name == 'conference'  # conference is a duplicate of inproceedings
221
  end
222 685:4481db876cdb luis
223 586:658cfb481618 chris
  def label
224
    l("field_bibtex_#{name}")
225
  end
226 685:4481db876cdb luis
227
  def self.fields (type)
228 1394:0f918e37e1d6 luis
    @@fields[ self.find(type).name ]
229 685:4481db876cdb luis
  end
230 542:23a9272bf766 luis
end
231 385:a6f8c0584a92 luis
# vendor/plugins/redmine_bibliography/app/models/publication.rb
232
233 328:aed18b463206 luis
class Publication < ActiveRecord::Base
234 428:9cfd7a1d848e luis
  unloadable
235 1068:e11d8d13ebc5 luis
236 571:e1699e8d6d69 luis
  has_many :authorships, :dependent => :destroy, :order => "auth_order ASC"
237 447:565f82b8ff9c luis
  has_many :authors, :through => :authorships, :uniq => true
238 1068:e11d8d13ebc5 luis
239 560:735388da579a luis
  has_one :bibtex_entry, :dependent => :destroy
240 376:ad71d0604ac2 luis
241
  validates_presence_of :title
242 686:b1debf464389 luis
  validates_length_of :authorships, :minimum => 1, :message => l("error_no_authors")
243 1287:1c3e2fb6793a luis
  validates_associated :bibtex_entry, :authorships
244 445:77f88379115a luis
245
  accepts_nested_attributes_for :authorships
246 446:995d4c99843d luis
  accepts_nested_attributes_for :authors, :allow_destroy => true
247 454:2f1a308c4c11 luis
  accepts_nested_attributes_for :bibtex_entry, :allow_destroy => true
248 1068:e11d8d13ebc5 luis
249 464:fbdfec975bfa luis
  has_and_belongs_to_many :projects, :uniq => true
250 1068:e11d8d13ebc5 luis
251 567:5404f7dfb4b3 chris
  before_save :set_initial_author_order
252 653:0c5674b65db0 chris
253 1212:1186340b4ad4 luis
  scope :visible, lambda {|*args| { :include => :projects,
254
                                    :conditions => Project.allowed_to_condition(args.shift || User.current, :view_publication, *args) } }
255 1087:74407a04925c luis
256 1080:5bd8c86cfa6a luis
  acts_as_activity_provider :type => 'publication',
257
                            :timestamp => "#{Publication.table_name}.created_at",
258 1087:74407a04925c luis
                            :find_options => {
259
                              :include => :projects,
260
                              :conditions => "#{Project.table_name}.id = projects_publications.project_id"
261
                            }
262 1080:5bd8c86cfa6a luis
263
  acts_as_event :title => Proc.new {|o| o.title },
264
                :datetime => :created_at,
265
                :type => 'publications',
266 1087:74407a04925c luis
                :author => nil,
267 1080:5bd8c86cfa6a luis
                #todo - need too move the cache from the helper to the model
268
                :description => Proc.new {|o| o.print_entry(:ieee)},
269 1087:74407a04925c luis
                :url => Proc.new {|o| {:controller => 'publications', :action => 'show', :id => o.id }}
270 1080:5bd8c86cfa6a luis
271
272 653:0c5674b65db0 chris
  # Ensure error message uses proper text instead of
273
  # bibtex_entry.entry_type (#268).  There has to be a better way to
274
  # do this!
275 1287:1c3e2fb6793a luis
  def self.human_attribute_name(k, *args)
276 653:0c5674b65db0 chris
    if k == 'bibtex_entry.entry_type'
277
      l(:field_entry_type)
278
    else
279
      super
280
    end
281
  end
282
283 1068:e11d8d13ebc5 luis
  def notify_authors_publication_added(project)
284 643:505fdac73166 luis
    self.authors.each do |author|
285 651:f029431de4dd luis
      Rails.logger.debug { "Sending mail to \"#{self.title}\" publication authors." }
286 1401:95bdaaab97ca luis
      Mailer.publication_added(author.user, self, project).deliver unless author.user.nil?
287 643:505fdac73166 luis
    end
288 666:865d079e5fa0 luis
  end
289 1068:e11d8d13ebc5 luis
290
  def notify_authors_publication_updated(project)
291 666:865d079e5fa0 luis
    self.authors.each do |author|
292
      Rails.logger.debug { "Sending mail to \"#{self.title}\" publication authors." }
293 1401:95bdaaab97ca luis
      Mailer.publication_updated(author.user, self, project).deliver unless author.user.nil?
294 666:865d079e5fa0 luis
    end
295 643:505fdac73166 luis
  end
296 1068:e11d8d13ebc5 luis
297
298 556:ca9e8e562ea7 luis
  def set_initial_author_order
299
    authorships = self.authorships
300 1068:e11d8d13ebc5 luis
301 556:ca9e8e562ea7 luis
    logger.debug { "Publication \"#{self.title}\" has #{authorships.size} authors." }
302 1068:e11d8d13ebc5 luis
303 556:ca9e8e562ea7 luis
    authorships.each_with_index do |authorship, index|
304
      if authorship.auth_order.nil?
305
         authorship.auth_order = index
306
      end
307 1068:e11d8d13ebc5 luis
    end
308 556:ca9e8e562ea7 luis
  end
309 1068:e11d8d13ebc5 luis
310 946:a0c9cc95bcf3 luis
  def print_bibtex_author_names
311 1068:e11d8d13ebc5 luis
    # this authors are correctly sorted because the authorships model
312 946:a0c9cc95bcf3 luis
    # already outputs the author names ASC by auth_order
313
    self.authorships.map{|a| a.name_on_paper}.join(' and ')
314 1068:e11d8d13ebc5 luis
  end
315
316 946:a0c9cc95bcf3 luis
  def print_entry(style)
317
    bib = BibTeX::Entry.new
318
319
    bib.author = self.print_bibtex_author_names
320
    bib.title = self.title
321
322 1068:e11d8d13ebc5 luis
    self.bibtex_entry.attributes.keys.sort.each do |key|
323 946:a0c9cc95bcf3 luis
      value = self.bibtex_entry.attributes[key].to_s
324
      next if key == 'id' or key == 'publication_id' or value == ""
325
326 1068:e11d8d13ebc5 luis
      if key == "entry_type"
327 1028:b8ae7b3af25a luis
        bib.type = BibtexEntryType.find(self.bibtex_entry.entry_type).name
328 946:a0c9cc95bcf3 luis
      else
329
        bib[key.to_sym] = value
330 1068:e11d8d13ebc5 luis
      end
331 946:a0c9cc95bcf3 luis
    end
332 1068:e11d8d13ebc5 luis
333 946:a0c9cc95bcf3 luis
    if style == :ieee
334 1584:8b1dc5e31dbc Chris
      cite = bib.to_citeproc
335
      cite_id = cite["id"]
336 1579:aba122ac2d40 Chris
      cp = CiteProc::Processor.new style: 'ieee', format: 'html'
337 1584:8b1dc5e31dbc Chris
      cp.import [cite]
338
      texts = cp.render :bibliography, id: cite_id
339
      texts[0]
340 1068:e11d8d13ebc5 luis
    else
341 1023:3d924264419a luis
      bibtex = bib.to_s :include => :meta_content
342
      bibtex.strip!
343 1068:e11d8d13ebc5 luis
    end
344 946:a0c9cc95bcf3 luis
  end
345 328:aed18b463206 luis
end