• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pulibrary / pdc_discovery / 6a05636c-0e7b-4c51-9e34-5c3e1a94c98e

06 Sep 2023 05:29PM UTC coverage: 96.478% (-0.1%) from 96.593%
6a05636c-0e7b-4c51-9e34-5c3e1a94c98e

Pull #501

circleci

hectorcorrea
Make sure Funder information is exposed on the SolrDocument class
Pull Request #501: Display Funder information in the Show page

6 of 6 new or added lines in 2 files covered. (100.0%)

2356 of 2442 relevant lines covered (96.48%)

181.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.6
/app/models/solr_document.rb
1
# frozen_string_literal: true
2

3
# rubocop:disable Metrics/ClassLength
4
class SolrDocument
1✔
5
  include Blacklight::Solr::Document
1✔
6

7
  field_semantics.merge!(
1✔
8
    title: 'title_tesim',
9
    contributor: 'author_tesim',
10
    format: 'genre_ssim',
11
    date: 'issue_date_ssim'
12
  )
13

14
  # self.unique_key = 'id'
15

16
  # Email uses the semantic field mappings below to generate the body of an email.
17
  SolrDocument.use_extension(Blacklight::Document::Email)
1✔
18

19
  # SMS uses the semantic field mappings below to generate the body of an SMS email.
20
  SolrDocument.use_extension(Blacklight::Document::Sms)
1✔
21

22
  # DublinCore uses the semantic field mappings below to assemble an OAI-compliant Dublin Core document
23
  # Semantic mappings of solr stored fields. Fields may be multi or
24
  # single valued. See Blacklight::Document::SemanticFields#field_semantics
25
  # and Blacklight::Document::SemanticFields#to_semantic_values
26
  # Recommendation: Use field names from Dublin Core
27
  use_extension(Blacklight::Document::DublinCore)
1✔
28

29
  ABSTRACT_FIELD = 'abstract_tsim'
1✔
30
  DESCRIPTION_FIELD = 'description_tsim'
1✔
31
  ISSUED_DATE_FIELD = 'issue_date_ssim'
1✔
32
  METHODS_FIELD = 'methods_tsim'
1✔
33
  TITLE_FIELD = 'title_tesim'
1✔
34

35
  # These icons map to CSS classes in Bootstrap
36
  ICONS = {
1✔
37
    "dataset" => "bi-stack",
38
    "moving image" => "bi-film",
39
    "software" => "bi-code-slash",
40
    "image" => "bi-image",
41
    "text" => "bi-card-text",
42
    "collection" => "bi-collection-fill",
43
    "article" => "bi-journal-text",
44
    "interactive resource" => "bi-pc-display-horizontal"
45
  }.freeze
46

47
  # .*?\s is lazy match so the regex stop as soon as space is found
48
  GLOBUS_URI_REGEX = /.*(https\:\/\/app.globus.org\/file-manager.*?\s).*/.freeze
1✔
49

50
  def id
1✔
51
    fetch('id')
240✔
52
  end
53

54
  def titles
1✔
55
    fetch(TITLE_FIELD, [])
62✔
56
  end
57

58
  def title
1✔
59
    titles.first
62✔
60
  end
61

62
  # Returns the list of author names (ordered if possible)
63
  def authors
1✔
64
    authors_ordered.map(&:value)
34✔
65
  end
66

67
  # Returns the list of authors with all their information including
68
  # name, ORCID, and affiliation. List is ordered if possible.
69
  def authors_ordered
1✔
70
    @authors_ordered ||= begin
175✔
71
      authors_json = fetch('authors_json_ss', nil)
52✔
72
      if authors_json
52✔
73
        # PDC Describe records contain this field;
74
        # get the author data and sort it.
75
        authors = JSON.parse(authors_json).map { |hash| Author.new(hash) }
14✔
76
        authors.sort_by(&:sequence)
5✔
77
      else
78
        # DataSpace record don't contain this field;
79
        # do the best we can with author_tesim value.
80
        names = fetch('author_tesim', [])
47✔
81
        names.map { |name| Author.new({ "value" => name }) }
293✔
82
      end
83
    end
84
  end
85

86
  # Returns a string with the authors and shortens it if there are more than 2 authors.
87
  # https://owl.purdue.edu/owl/research_and_citation/apa_style/apa_formatting_and_style_guide/in_text_citations_author_authors.html
88
  def authors_et_al
1✔
89
    authors_all = authors
18✔
90
    if authors_all.count <= 2
18✔
91
      authors_all.join(" & ")
8✔
92
    else
93
      authors_all.first + " et al."
10✔
94
    end
95
  end
96

97
  # Create an author hash when we only have an author name (e.g. for records coming from DataSpace)
98
  # In this case order/sequence cannot be determined.
99
  def author_from_name(name)
1✔
100
    {
101
      "value" => name,
×
102
      "name_type" => "Personal",
103
      "given_name" => nil,
104
      "family_name" => nil,
105
      "identifier" => nil,
106
      "affiliations" => [],
107
      "sequence" => 0
108
    }
109
  end
110

111
  def creators
1✔
112
    fetch('creator_tesim', [])
16✔
113
  end
114

115
  def community_path
1✔
116
    communities.first
×
117
  end
118

119
  def communities
1✔
120
    fetch("communities_ssim", [])
28✔
121
  end
122

123
  def subcommunities
1✔
124
    fetch("subcommunities_ssim", [])
25✔
125
  end
126

127
  def collection_name
1✔
128
    fetch("collection_name_ssi", "")
×
129
  end
130

131
  def collection_tags
1✔
132
    fetch("collection_tag_ssim", [])
32✔
133
  end
134

135
  def contributors
1✔
136
    fetch("contributor_tsim", [])
16✔
137
  end
138

139
  def accessioned_dates
1✔
140
    fetch("date_accessioned_ssim", [])
16✔
141
  end
142

143
  def accessioned_date
1✔
144
    accessioned_dates.first
16✔
145
  end
146

147
  def issued_dates
1✔
148
    fetch(ISSUED_DATE_FIELD, [])
62✔
149
  end
150

151
  def issued_date
1✔
152
    issued_dates.first
62✔
153
  end
154

155
  def abstracts
1✔
156
    fetch(ABSTRACT_FIELD, [])
16✔
157
  end
158

159
  def abstract
1✔
160
    abstracts.first
×
161
  end
162

163
  def descriptions
1✔
164
    fetch(DESCRIPTION_FIELD, [])
29✔
165
  end
166

167
  def description
1✔
168
    descriptions.first
13✔
169
  end
170

171
  def methods
1✔
172
    fetch(METHODS_FIELD, [])
×
173
  end
174

175
  def data_source
1✔
176
    fetch("data_source_ssi", "dataspace")
105✔
177
  end
178

179
  def pdc_describe_record?
1✔
180
    data_source == "pdc_describe"
18✔
181
  end
182

183
  def files
1✔
184
    @files ||= begin
50✔
185
      data = JSON.parse(fetch("files_ss", "[]"))
18✔
186
      data.map { |file| DatasetFile.from_hash(file, data_source) }.sort_by(&:sequence)
54✔
187
    end
188
  end
189

190
  # Returns an array with the counts by file extension
191
  # e.g. [{extension: "txt", file_count: 3}, {extension: "csv", file_count: 1}]
192
  def file_counts
1✔
193
    groups = files.group_by(&:extension)
19✔
194
    groups.map { |key, value| { extension: key, file_count: value.count } }.sort_by { |group| -group[:file_count] }
85✔
195
  end
196

197
  def funders
1✔
198
    funders_string = fetch("funders_ss", "[]")
×
199
    @funders = JSON.parse(funders_string)
×
200
    @funders
×
201
  end
202

203
  def table_of_contents
1✔
204
    fetch("tableofcontents_tesim", [])
16✔
205
  end
206

207
  def referenced_by
1✔
208
    fetch("referenced_by_ssim", [])
16✔
209
  end
210

211
  def uri
1✔
212
    fetch("uri_ssim", [])
77✔
213
  end
214

215
  def doi_url
1✔
216
    uri.each do |link|
48✔
217
      return link if link.downcase.start_with?('https://doi.org/')
54✔
218
    end
219
    nil
220
  end
221

222
  def doi_value
1✔
223
    doi_url&.gsub('https://doi.org/', '')
16✔
224
  end
225

226
  def format
1✔
227
    fetch("format_ssim", [])
16✔
228
  end
229

230
  def globus_uri
1✔
231
    # First we try to use the value indexed (only exists for PDC Describe records)
232
    indexed_uri = fetch("globus_uri_ssi", nil)
18✔
233
    return indexed_uri unless indexed_uri.nil?
18✔
234

235
    # ...then check the links indexed to see if one of them looks like a Globus URI
236
    uri.each do |link|
13✔
237
      return link if link.downcase.start_with?('https://app.globus.org/')
16✔
238
    end
239

240
    # ...if all fails, see if there is a Globus URI in the description
241
    globus_uri_from_description
10✔
242
  end
243

244
  def globus_uri_from_description
1✔
245
    match = description&.match(GLOBUS_URI_REGEX)
13✔
246
    match.captures.first.strip if match
13✔
247
  end
248

249
  def extent
1✔
250
    fetch("extent_ssim", [])
16✔
251
  end
252

253
  def medium
1✔
254
    fetch("medium_ssim", [])
16✔
255
  end
256

257
  def mimetype
1✔
258
    fetch("mimetype_ssim", [])
16✔
259
  end
260

261
  def language
1✔
262
    fetch("language_ssim", [])
16✔
263
  end
264

265
  def publisher
1✔
266
    fetch("publisher_ssim", [])
32✔
267
  end
268

269
  def publisher_place
1✔
270
    fetch("publisher_place_ssim", [])
16✔
271
  end
272

273
  def publisher_corporate
1✔
274
    fetch("publisher_corporate_ssim", [])
16✔
275
  end
276

277
  def related_identifiers
1✔
278
    @related_identifiers ||= begin
16✔
279
      hash = JSON.parse(fetch("pdc_describe_json_ss", "{}"))
16✔
280
      hash.dig("resource", "related_objects") || []
16✔
281
    end
282
  end
283

284
  def relation
1✔
285
    fetch("relation_ssim", [])
16✔
286
  end
287

288
  def relation_is_format_of
1✔
289
    fetch("relation_is_format_of_ssim", [])
16✔
290
  end
291

292
  def relation_has_format
1✔
293
    fetch("relation_has_format_ssim", [])
16✔
294
  end
295

296
  def relation_is_part_of
1✔
297
    fetch("relation_is_part_of_ssim", [])
16✔
298
  end
299

300
  def relation_is_part_of_series
1✔
301
    fetch("relation_is_part_of_series_ssim", [])
16✔
302
  end
303

304
  def relation_has_part
1✔
305
    fetch("relation_has_part_ssim", [])
16✔
306
  end
307

308
  def relation_is_version_of
1✔
309
    fetch("relation_is_version_of_ssim", [])
16✔
310
  end
311

312
  def relation_has_version
1✔
313
    fetch("relation_has_version_ssim", [])
16✔
314
  end
315

316
  def relation_is_based_on
1✔
317
    fetch("relation_is_based_on_ssim", [])
16✔
318
  end
319

320
  def relation_is_referenced_by
1✔
321
    fetch("relation_is_referenced_by_ssim", [])
16✔
322
  end
323

324
  def relation_is_required_by
1✔
325
    fetch("relation_is_required_by_ssim", [])
16✔
326
  end
327

328
  def relation_requires
1✔
329
    fetch("relation_requires_ssim", [])
16✔
330
  end
331

332
  def relation_replaces
1✔
333
    fetch("relation_replaces_ssim", [])
16✔
334
  end
335

336
  def relation_is_replaced_by
1✔
337
    fetch("relation_is_replaced_by_ssim", [])
16✔
338
  end
339

340
  def relation_uri
1✔
341
    fetch("relation_uri_ssim", [])
16✔
342
  end
343

344
  def rights
1✔
345
    fetch("rights_ssim", [])
12✔
346
  end
347

348
  def rights_uri
1✔
349
    fetch("rights_uri_ssim", [])
12✔
350
  end
351

352
  # For PDC Describe records we have a single value for the name and the uri
353
  # and we can safely assume they are related.
354
  def rights_name_and_uri
1✔
355
    name = fetch("rights_name_ssi", nil)
24✔
356
    uri = fetch("rights_uri_ssi", nil)
24✔
357
    return nil if name.nil? || uri.nil?
24✔
358
    { name: name, uri: uri }
12✔
359
  end
360

361
  def rights_holder
1✔
362
    fetch("rights_holder_ssim", [])
16✔
363
  end
364

365
  def subject
1✔
366
    if pdc_describe_record?
18✔
367
      fetch("subject_all_ssim", [])
5✔
368
    else
369
      fetch("subject_tesim", [])
13✔
370
    end
371
  end
372

373
  def subject_classification
1✔
374
    fetch("subject_classification_tesim", [])
16✔
375
  end
376

377
  def subject_ddc
1✔
378
    fetch("subject_ddc_tesim", [])
16✔
379
  end
380

381
  def subject_lcc
1✔
382
    fetch("subject_lcc_tesim", [])
16✔
383
  end
384

385
  def subject_lcsh
1✔
386
    fetch("subject_lcsh_tesim", [])
16✔
387
  end
388

389
  def subject_mesh
1✔
390
    fetch("subject_mesh_tesim", [])
16✔
391
  end
392

393
  def subject_other
1✔
394
    fetch("subject_other_tesim", [])
16✔
395
  end
396

397
  def alternative_title
1✔
398
    fetch("alternative_title_tesim", [])
16✔
399
  end
400

401
  def genres
1✔
402
    fetch("genre_ssim", []).sort
46✔
403
  end
404

405
  # Sometimes we need a single genre for an item, even though an item may have more than one.
406
  # This method makes sure we always get the same value (the first one from a sorted list).
407
  def genre
1✔
408
    genres.first
30✔
409
  end
410

411
  def peer_review_status
1✔
412
    fetch("peer_review_status_ssim", [])
16✔
413
  end
414

415
  def translator
1✔
416
    fetch("translator_ssim", [])
16✔
417
  end
418

419
  def isan
1✔
420
    fetch("isan_ssim", [])
16✔
421
  end
422

423
  def access_rights
1✔
424
    fetch("access_rights_ssim", [])
16✔
425
  end
426

427
  def funding_agency
1✔
428
    fetch("funding_agency_ssim", [])
16✔
429
  end
430

431
  def provenance
1✔
432
    fetch("provenance_ssim", [])
16✔
433
  end
434

435
  def license
1✔
436
    fetch("license_ssim", [])
16✔
437
  end
438

439
  def accrual_method
1✔
440
    fetch("accrual_method_ssim", [])
16✔
441
  end
442

443
  def accrual_periodicity
1✔
444
    fetch("accrual_periodicity_ssim", [])
16✔
445
  end
446

447
  def accrual_policy
1✔
448
    fetch("accrual_policy_ssim", [])
16✔
449
  end
450

451
  def audience
1✔
452
    fetch("audience_ssim", [])
16✔
453
  end
454

455
  def available
1✔
456
    fetch("available_ssim", [])
16✔
457
  end
458

459
  def bibliographic_citation
1✔
460
    fetch("bibliographic_citation_ssim", [])
16✔
461
  end
462

463
  def conforms_to
1✔
464
    fetch("conforms_to_ssim", [])
16✔
465
  end
466

467
  def coverage
1✔
468
    fetch("coverage_tesim", [])
16✔
469
  end
470

471
  def spatial_coverage
1✔
472
    fetch("spatial_coverage_tesim", [])
16✔
473
  end
474

475
  def temporal_coverage
1✔
476
    fetch("temporal_coverage_tesim", [])
16✔
477
  end
478

479
  def dates_created
1✔
480
    fetch("date_created_ssim", [])
16✔
481
  end
482

483
  def date_created
1✔
484
    dates_created.first
16✔
485
  end
486

487
  def dates_submitted
1✔
488
    fetch("date_submitted_ssim", [])
16✔
489
  end
490

491
  def date_submitted
1✔
492
    dates_submitted.first
16✔
493
  end
494

495
  def dates_accepted
1✔
496
    fetch("date_accepted_ssim", [])
16✔
497
  end
498

499
  def date_accepted
1✔
500
    dates_accepted.first
16✔
501
  end
502

503
  def dates_copyrighted
1✔
504
    fetch("copyright_date_ssim", [])
16✔
505
  end
506

507
  def date_copyrighted
1✔
508
    dates_copyrighted.first
16✔
509
  end
510

511
  def dates_modified
1✔
512
    fetch("date_modified_ssim", [])
16✔
513
  end
514

515
  def date_modified
1✔
516
    dates_modified.first
16✔
517
  end
518

519
  def dates_valid
1✔
520
    fetch("date_valid_ssim", [])
16✔
521
  end
522

523
  def education_level
1✔
524
    fetch("education_level_ssim", [])
16✔
525
  end
526

527
  def other_identifier
1✔
528
    fetch("other_identifier_ssim", [])
16✔
529
  end
530

531
  def instructional_method
1✔
532
    fetch("instructional_method_ssim", [])
16✔
533
  end
534

535
  def mediator
1✔
536
    fetch("mediator_ssim", [])
16✔
537
  end
538

539
  def source
1✔
540
    fetch("source_ssim", [])
16✔
541
  end
542

543
  def domains
1✔
544
    fetch("domain_ssim", "")
27✔
545
  end
546

547
  def icon_css
1✔
548
    ICONS[genre&.downcase] || 'bi-file-earmark-fill'
16✔
549
  end
550

551
  # Returns a DatasetCitation object for the current document
552
  def citation
1✔
553
    @citation ||= begin
64✔
554
      year_available = fetch('year_available_itsi', nil)
16✔
555
      years = year_available ? [year_available.to_s] : []
16✔
556
      DatasetCitation.new(authors, years, title, 'Data set', publisher.first, doi_url)
16✔
557
    end
558
  end
559

560
  # Returns a string with the indicated citation style (e.g. APA or BibTeX)
561
  def cite(style)
1✔
562
    citation.to_s(style)
48✔
563
  end
564

565
  # Returns the ID for a BibTeX citation for this document.
566
  # rubocop:disable Rails/Delegate
567
  def bibtex_id
1✔
568
    citation.bibtex_id
×
569
  end
570
  # rubocop:enable Rails/Delegate
571
end
572
# rubocop:enable Metrics/ClassLength
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc