labimotion 2.2.0.rc19 → 2.2.0.rc21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/labimotion/apis/generic_element_api.rb +1 -0
- data/lib/labimotion/apis/labimotion_doi_api.rb +22 -10
- data/lib/labimotion/apis/labimotion_template_browse_api.rb +11 -1
- data/lib/labimotion/helpers/element_helpers.rb +21 -15
- data/lib/labimotion/models/concerns/element_fetchable.rb +2 -2
- data/lib/labimotion/models/concerns/template_doi.rb +20 -0
- data/lib/labimotion/models/element.rb +2 -2
- data/lib/labimotion/usecases/build_template_doi_xml.rb +19 -12
- data/lib/labimotion/usecases/release_template_doi.rb +43 -17
- data/lib/labimotion/usecases/update_template_publication_metadata.rb +25 -1
- data/lib/labimotion/utils/search.rb +2 -2
- data/lib/labimotion/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 006f7a0d5c1bc994e1ed1be862881e579b83a91844e176858571471a4225a6e5
|
|
4
|
+
data.tar.gz: 9d40a31313cc7717bd0a9cb971e457bc6c2ad93a3818a3ad305dec05ad9bc406
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 399cb835f06e3cc7e30a8c59f3e64ae7738da938a7bb4a68e3ffd9c331854e36c84743b90a07769407c910d2b49042996734d2572517932a97869a18f0e6174b
|
|
7
|
+
data.tar.gz: 8ce94d81213aba4205aff04328c3eba89ca095b84301ddf7eee22497e0964635a0998735175f47fa00642f4d47d481e9ef0aa95bb1b04357705a1c1ad21c3c6b
|
|
@@ -432,6 +432,7 @@ module Labimotion
|
|
|
432
432
|
desc 'Return serialized elements of current user'
|
|
433
433
|
params do
|
|
434
434
|
optional :collection_id, type: Integer, desc: 'Collection id'
|
|
435
|
+
optional :sync_collection_id, type: Integer, desc: 'SyncCollectionsUser id'
|
|
435
436
|
optional :el_type, type: String, desc: 'element klass name'
|
|
436
437
|
optional :from_date, type: Integer, desc: 'created_date from in ms'
|
|
437
438
|
optional :to_date, type: Integer, desc: 'created_date to in ms'
|
|
@@ -7,6 +7,8 @@ module Labimotion
|
|
|
7
7
|
# rubocop:disable Metrics/BlockLength
|
|
8
8
|
# Grape route and helper DSL blocks are necessarily large.
|
|
9
9
|
KLASS_TYPES = Labimotion::TemplateDoiHelpers::KLASS_BY_TYPE.keys.freeze
|
|
10
|
+
# Publication fields exposed on the public (anonymous) DOI endpoints.
|
|
11
|
+
PUBLIC_PUBLICATION_KEYS = %w[title description authors contributor license].freeze
|
|
10
12
|
|
|
11
13
|
helpers do
|
|
12
14
|
def resolve_klass!(type, id)
|
|
@@ -41,25 +43,36 @@ module Labimotion
|
|
|
41
43
|
)
|
|
42
44
|
end
|
|
43
45
|
|
|
44
|
-
# Public, read-only view of one released DOI version
|
|
45
|
-
|
|
46
|
+
# Public, read-only view of one released DOI version, carrying the
|
|
47
|
+
# publication metadata that version was released with.
|
|
48
|
+
def released_doi_version(record, doi)
|
|
46
49
|
full = doi.full_doi
|
|
47
50
|
{
|
|
48
51
|
doi: full,
|
|
49
52
|
doi_url: "https://dx.doi.org/#{full}",
|
|
50
53
|
version: ::Doi.labimotion_doi_version(doi),
|
|
51
|
-
minted_at: doi.minted_at
|
|
54
|
+
minted_at: doi.minted_at,
|
|
55
|
+
publication: released_publication(record, doi)
|
|
52
56
|
}
|
|
53
57
|
end
|
|
54
58
|
|
|
59
|
+
# The snapshot taken when this version was released. DOIs released before
|
|
60
|
+
# snapshots were kept have none, and fall back to the template's current
|
|
61
|
+
# publication — the best available answer for them.
|
|
62
|
+
def released_publication(record, doi)
|
|
63
|
+
publication = ::Doi.labimotion_doi_publication(doi).presence ||
|
|
64
|
+
(record.properties_template || {})['publication']
|
|
65
|
+
publication.is_a?(Hash) ? publication.slice(*PUBLIC_PUBLICATION_KEYS) : {}
|
|
66
|
+
end
|
|
67
|
+
|
|
55
68
|
# Public payload for a template that has at least one released DOI: the
|
|
56
69
|
# latest released DOI promoted to the top level, plus its publication
|
|
57
|
-
# metadata, hub deep-link and every released version.
|
|
58
|
-
#
|
|
70
|
+
# metadata, hub deep-link and every released version. Each version brings
|
|
71
|
+
# its own publication, so the top-level one is the latest release's rather
|
|
72
|
+
# than the template's work-in-progress. `record_id` matches the hub grid's
|
|
73
|
+
# row id (identifier || uuid) so the frontend can merge it.
|
|
59
74
|
def released_template_doi(record, dois)
|
|
60
|
-
versions = dois.sort_by(&:id).map { |doi| released_doi_version(doi) }
|
|
61
|
-
publication = (record.properties_template || {})['publication']
|
|
62
|
-
publication = publication.is_a?(Hash) ? publication.slice('title', 'description', 'authors', 'license') : {}
|
|
75
|
+
versions = dois.sort_by(&:id).map { |doi| released_doi_version(record, doi) }
|
|
63
76
|
versions.last.merge(
|
|
64
77
|
record_id: record.try(:identifier).presence || record.try(:uuid).presence || record.id,
|
|
65
78
|
identifier: record.try(:identifier),
|
|
@@ -68,7 +81,6 @@ module Labimotion
|
|
|
68
81
|
template_version: record.try(:version),
|
|
69
82
|
next_doi_version: ::Doi.labimotion_version_segment(record),
|
|
70
83
|
template_url: Labimotion::TemplateDoiHelpers.template_url(record),
|
|
71
|
-
publication: publication,
|
|
72
84
|
versions: versions
|
|
73
85
|
)
|
|
74
86
|
end
|
|
@@ -125,7 +137,7 @@ module Labimotion
|
|
|
125
137
|
version: ::Doi.labimotion_doi_version(doi),
|
|
126
138
|
full_doi: doi.full_doi,
|
|
127
139
|
minted: doi.minted == true,
|
|
128
|
-
xml: Labimotion::BuildTemplateDoiXml.new(record, doi
|
|
140
|
+
xml: Labimotion::BuildTemplateDoiXml.new(record, doi).call
|
|
129
141
|
}
|
|
130
142
|
end
|
|
131
143
|
{ versions: versions }
|
|
@@ -9,6 +9,8 @@ module Labimotion
|
|
|
9
9
|
class LabimotionTemplateBrowseAPI < Grape::API
|
|
10
10
|
KLASS_BY_TYPE = Labimotion::TemplateDoiHelpers::KLASS_BY_TYPE
|
|
11
11
|
KLASS_TYPES = KLASS_BY_TYPE.keys.freeze
|
|
12
|
+
# Publication fields exposed alongside a template / its released DOIs.
|
|
13
|
+
PUBLICATION_KEYS = %w[title description authors contributor license].freeze
|
|
12
14
|
# type => [revision model, foreign key to the klass]
|
|
13
15
|
REVISION_BY_TYPE = {
|
|
14
16
|
'element' => [::Labimotion::ElementKlassesRevision, :element_klass_id],
|
|
@@ -76,7 +78,14 @@ module Labimotion
|
|
|
76
78
|
# The template's DOI publication metadata (shown alongside the DOI).
|
|
77
79
|
def template_publication(record)
|
|
78
80
|
pub = (record.properties_template || {})['publication']
|
|
79
|
-
pub.is_a?(Hash) ? pub.slice(
|
|
81
|
+
pub.is_a?(Hash) ? pub.slice(*PUBLICATION_KEYS) : {}
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# The publication a released DOI was published with. Falls back to the
|
|
85
|
+
# template's current metadata for DOIs released before snapshots were kept.
|
|
86
|
+
def released_publication(record, doi)
|
|
87
|
+
pub = ::Doi.labimotion_doi_publication(doi)
|
|
88
|
+
pub.is_a?(Hash) && pub.any? ? pub.slice(*PUBLICATION_KEYS) : template_publication(record)
|
|
80
89
|
end
|
|
81
90
|
|
|
82
91
|
# Released (minted) DOIs of the template, each tagged with its DOI version
|
|
@@ -88,6 +97,7 @@ module Labimotion
|
|
|
88
97
|
full = doi.full_doi
|
|
89
98
|
{ version: ::Doi.labimotion_doi_version(doi), doi: full,
|
|
90
99
|
doi_url: "https://dx.doi.org/#{full}", minted_at: doi.minted_at,
|
|
100
|
+
publication: released_publication(record, doi),
|
|
91
101
|
xml: Labimotion::BuildTemplateDoiXml.new(record, doi).call }
|
|
92
102
|
end
|
|
93
103
|
end
|
|
@@ -215,7 +215,7 @@ module Labimotion
|
|
|
215
215
|
layer, field = params[:sort_column].split('.')
|
|
216
216
|
|
|
217
217
|
element_klass = Labimotion::ElementKlass.find_by(name: params[:el_type])
|
|
218
|
-
allowed_fields = element_klass
|
|
218
|
+
allowed_fields = element_klass.properties_release.dig(Labimotion::Prop::LAYERS, layer, Labimotion::Prop::FIELDS)&.pluck('field') || []
|
|
219
219
|
|
|
220
220
|
if field.in?(allowed_fields)
|
|
221
221
|
query = ActiveRecord::Base.sanitize_sql(
|
|
@@ -247,21 +247,27 @@ module Labimotion
|
|
|
247
247
|
end
|
|
248
248
|
|
|
249
249
|
def list_serialized_elements(params, current_user)
|
|
250
|
-
|
|
251
|
-
|
|
250
|
+
collection_id =
|
|
252
251
|
if params[:collection_id]
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
252
|
+
Collection
|
|
253
|
+
.belongs_to_or_shared_by(current_user.id, current_user.group_ids)
|
|
254
|
+
.find_by(id: params[:collection_id])&.id
|
|
255
|
+
elsif params[:sync_collection_id]
|
|
256
|
+
current_user
|
|
257
|
+
.all_sync_in_collections_users
|
|
258
|
+
.find_by(id: params[:sync_collection_id])&.collection&.id
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
scope =
|
|
262
|
+
if collection_id
|
|
263
|
+
Labimotion::Element
|
|
264
|
+
.joins(:element_klass, :collections_elements)
|
|
265
|
+
.where(
|
|
266
|
+
element_klasses: { name: params[:el_type] },
|
|
267
|
+
collections_elements: { collection_id: collection_id },
|
|
268
|
+
).includes(:tag, collections: :sync_collections_users)
|
|
262
269
|
else
|
|
263
|
-
|
|
264
|
-
scope = Labimotion::Element.for_user(current_user.id)
|
|
270
|
+
Labimotion::Element.none
|
|
265
271
|
end
|
|
266
272
|
|
|
267
273
|
## TO DO: refactor labimotion
|
|
@@ -272,7 +278,7 @@ module Labimotion
|
|
|
272
278
|
layer, field = params[:sort_column].split('.')
|
|
273
279
|
|
|
274
280
|
element_klass = Labimotion::ElementKlass.find_by(name: params[:el_type])
|
|
275
|
-
allowed_fields = element_klass
|
|
281
|
+
allowed_fields = element_klass.properties_release.dig(Labimotion::Prop::LAYERS, layer, Labimotion::Prop::FIELDS)&.pluck('field') || []
|
|
276
282
|
|
|
277
283
|
if field.in?(allowed_fields)
|
|
278
284
|
query = ActiveRecord::Base.sanitize_sql(
|
|
@@ -26,9 +26,9 @@ module Labimotion
|
|
|
26
26
|
joins(collections: :user).where(collections: { user_id: user_id })
|
|
27
27
|
)
|
|
28
28
|
|
|
29
|
-
# Shared records
|
|
29
|
+
# Shared (synced) records
|
|
30
30
|
shared = apply_filters.call(
|
|
31
|
-
|
|
31
|
+
joins(collections: :sync_collections_users).where(sync_collections_users: { user_id: user_id })
|
|
32
32
|
)
|
|
33
33
|
|
|
34
34
|
# Combine (remove duplicates), order, and limit
|
|
@@ -82,6 +82,26 @@ module Labimotion
|
|
|
82
82
|
{ 'labimotion' => { 'doi_version' => labimotion_version_segment(record, version) } }
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
+
# The publication metadata a released template DOI was published with.
|
|
86
|
+
# Nil while the DOI is still reserved, and for DOIs released before
|
|
87
|
+
# snapshots were kept — callers fall back to the template's current
|
|
88
|
+
# publication in both cases.
|
|
89
|
+
def labimotion_doi_publication(doi)
|
|
90
|
+
doi.metadata.to_h.dig('labimotion', 'publication')
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# The DOI's metadata with the publication snapshotted into it, keeping
|
|
94
|
+
# the DOI version already stamped there. Taken at release: the template's
|
|
95
|
+
# publication keeps being edited for the next version, and this version
|
|
96
|
+
# must stop tracking those edits.
|
|
97
|
+
def labimotion_metadata_with_publication(doi, publication)
|
|
98
|
+
metadata = doi.metadata.to_h
|
|
99
|
+
# Deep-duped: the snapshot must not alias the template's publication,
|
|
100
|
+
# which goes on being edited for the next version.
|
|
101
|
+
labimotion = (metadata['labimotion'] || {}).merge('publication' => publication.deep_dup)
|
|
102
|
+
metadata.merge('labimotion' => labimotion)
|
|
103
|
+
end
|
|
104
|
+
|
|
85
105
|
def labimotion_suffix_parts(record)
|
|
86
106
|
# identifier/uuid may both be blank for a draft, which would collapse the
|
|
87
107
|
# scope (colliding across templates). Fall back to the stable record id so
|
|
@@ -141,9 +141,9 @@ module Labimotion
|
|
|
141
141
|
joins(collections: :user).where(collections: { user_id: user_id })
|
|
142
142
|
)
|
|
143
143
|
|
|
144
|
-
# Shared elements
|
|
144
|
+
# Shared (synced) elements
|
|
145
145
|
shared = apply_filters.call(
|
|
146
|
-
|
|
146
|
+
joins(collections: :sync_collections_users).where(sync_collections_users: { user_id: user_id })
|
|
147
147
|
)
|
|
148
148
|
|
|
149
149
|
# Combine (remove duplicates), order, and limit
|
|
@@ -23,10 +23,9 @@ module Labimotion
|
|
|
23
23
|
'dataset' => 'LabIMotion Dataset Template'
|
|
24
24
|
}.freeze
|
|
25
25
|
|
|
26
|
-
def initialize(record, doi = nil
|
|
26
|
+
def initialize(record, doi = nil)
|
|
27
27
|
@record = record
|
|
28
28
|
@doi = doi || ::Doi.labimotion_latest_doi(record)
|
|
29
|
-
@current_user = current_user
|
|
30
29
|
end
|
|
31
30
|
|
|
32
31
|
# Returns the XML string, or nil when no DOI has been reserved yet.
|
|
@@ -89,23 +88,31 @@ module Labimotion
|
|
|
89
88
|
end
|
|
90
89
|
end
|
|
91
90
|
|
|
92
|
-
# The
|
|
93
|
-
# (no contributors block) when
|
|
91
|
+
# The author picked from the author list, rendered as a DataCite
|
|
92
|
+
# "Researcher" contributor. Nil (no contributors block) when none has been
|
|
93
|
+
# picked — it is never inferred from whoever happens to be publishing.
|
|
94
94
|
def contributor
|
|
95
|
-
|
|
96
|
-
return nil unless
|
|
95
|
+
picked = publication['contributor']
|
|
96
|
+
return nil unless picked.is_a?(Hash)
|
|
97
97
|
|
|
98
|
-
given =
|
|
99
|
-
family =
|
|
98
|
+
given = picked['givenName'].to_s.strip
|
|
99
|
+
family = picked['familyName'].to_s.strip
|
|
100
100
|
return nil if given.empty? && family.empty?
|
|
101
101
|
|
|
102
|
-
|
|
103
|
-
{ 'givenName' => h(given), 'familyName' => h(family), 'orcid' => h(orcid) }
|
|
102
|
+
{ 'givenName' => h(given), 'familyName' => h(family), 'orcid' => h(picked['orcid'].to_s.strip) }
|
|
104
103
|
end
|
|
105
104
|
|
|
105
|
+
# What this DOI renders: the snapshot taken when it was released, so every
|
|
106
|
+
# released version keeps showing the metadata it was published with rather
|
|
107
|
+
# than the template's latest. A DOI that is still reserved has no snapshot
|
|
108
|
+
# and renders the template's current publication, which is what is still
|
|
109
|
+
# being edited for it.
|
|
106
110
|
def publication
|
|
107
|
-
@publication ||=
|
|
108
|
-
|
|
111
|
+
@publication ||= ::Doi.labimotion_doi_publication(@doi).presence || record_publication
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def record_publication
|
|
115
|
+
(@record.properties_template.is_a?(Hash) ? @record.properties_template['publication'] : nil) || {}
|
|
109
116
|
end
|
|
110
117
|
|
|
111
118
|
def h(value)
|
|
@@ -24,7 +24,8 @@ module Labimotion
|
|
|
24
24
|
return failure('doi not reserved') if @doi.nil?
|
|
25
25
|
return self if @doi.minted
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
missing = missing_metadata
|
|
28
|
+
return failure("publication metadata is incomplete: #{missing.join(', ')}") if missing.any?
|
|
28
29
|
|
|
29
30
|
publish_at_datacite
|
|
30
31
|
self
|
|
@@ -37,22 +38,33 @@ module Labimotion
|
|
|
37
38
|
private
|
|
38
39
|
|
|
39
40
|
def publish_at_datacite
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
# DataCite requires the metadata to exist before the DOI can be minted.
|
|
43
|
-
metadata = mds.upload_metadata(BuildTemplateDoiXml.new(record, doi, current_user).call)
|
|
44
|
-
return failure(datacite_error('metadata upload', metadata)) unless metadata.is_a?(Net::HTTPSuccess)
|
|
45
|
-
|
|
46
|
-
response = mds.mint(doi.full_doi, TemplateDoiHelpers.template_url(record))
|
|
47
|
-
return failure(datacite_error('mint', response)) unless response.is_a?(Net::HTTPSuccess)
|
|
48
|
-
end
|
|
41
|
+
datacite_failure = send_to_datacite? ? mint_at_datacite : nil
|
|
42
|
+
return failure(datacite_failure) if datacite_failure
|
|
49
43
|
|
|
50
44
|
ActiveRecord::Base.transaction do
|
|
51
|
-
|
|
45
|
+
# The publication is snapshotted onto the DOI as it is minted, so this
|
|
46
|
+
# version keeps rendering what it was published with once the template's
|
|
47
|
+
# metadata moves on to the next version.
|
|
48
|
+
doi.update!(minted: true, minted_at: Time.current,
|
|
49
|
+
metadata: ::Doi.labimotion_metadata_with_publication(doi, publication))
|
|
52
50
|
stamp_release_on_record
|
|
53
51
|
end
|
|
54
52
|
end
|
|
55
53
|
|
|
54
|
+
# Uploads the metadata and mints the DOI at DataCite. Returns an error
|
|
55
|
+
# message, or nil when both calls succeeded.
|
|
56
|
+
def mint_at_datacite
|
|
57
|
+
mds = ::Repo::Datacite::Mds.new
|
|
58
|
+
# DataCite requires the metadata to exist before the DOI can be minted.
|
|
59
|
+
metadata = mds.upload_metadata(BuildTemplateDoiXml.new(record, doi).call)
|
|
60
|
+
return datacite_error('metadata upload', metadata) unless metadata.is_a?(Net::HTTPSuccess)
|
|
61
|
+
|
|
62
|
+
response = mds.mint(doi.full_doi, TemplateDoiHelpers.template_url(record))
|
|
63
|
+
return datacite_error('mint', response) unless response.is_a?(Net::HTTPSuccess)
|
|
64
|
+
|
|
65
|
+
nil
|
|
66
|
+
end
|
|
67
|
+
|
|
56
68
|
def datacite_error(step, response)
|
|
57
69
|
status = response.respond_to?(:code) ? response.code : 'unknown'
|
|
58
70
|
"datacite #{step} failed (status #{status})"
|
|
@@ -73,13 +85,27 @@ module Labimotion
|
|
|
73
85
|
record.update!(attrs) if attrs.any?
|
|
74
86
|
end
|
|
75
87
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
88
|
+
# Everything the publication form owns that DataCite needs, named so the
|
|
89
|
+
# modal can say what is still missing. The contributor is one of the
|
|
90
|
+
# authors and has to be picked in the form — a DOI is never released
|
|
91
|
+
# crediting whoever happened to press the button.
|
|
92
|
+
def missing_metadata
|
|
93
|
+
missing = %w[title description].reject { |key| publication[key].to_s.strip.present? }
|
|
94
|
+
missing << 'authors' unless Array(publication['authors']).any? { |author| named?(author) }
|
|
95
|
+
missing << 'contributor' unless named?(publication['contributor'])
|
|
96
|
+
missing
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def named?(person)
|
|
100
|
+
person.is_a?(Hash) && person['familyName'].to_s.strip.present?
|
|
101
|
+
end
|
|
79
102
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
103
|
+
# The template's current publication metadata — what this release publishes.
|
|
104
|
+
def publication
|
|
105
|
+
@publication ||= begin
|
|
106
|
+
pub = record.properties_template.is_a?(Hash) ? record.properties_template['publication'] : nil
|
|
107
|
+
pub.is_a?(Hash) ? pub : {}
|
|
108
|
+
end
|
|
83
109
|
end
|
|
84
110
|
|
|
85
111
|
def failure(message)
|
|
@@ -7,7 +7,7 @@ module Labimotion
|
|
|
7
7
|
class UpdateTemplatePublicationMetadata
|
|
8
8
|
include TemplateDoiHelpers
|
|
9
9
|
|
|
10
|
-
ALLOWED_KEYS = %w[title description authors license].freeze
|
|
10
|
+
ALLOWED_KEYS = %w[title description authors contributor license].freeze
|
|
11
11
|
|
|
12
12
|
attr_reader :record, :current_user, :publication, :error
|
|
13
13
|
|
|
@@ -39,9 +39,33 @@ module Labimotion
|
|
|
39
39
|
def normalized_publication
|
|
40
40
|
slice = publication.stringify_keys.slice(*ALLOWED_KEYS)
|
|
41
41
|
slice['authors'] = Array(slice['authors']).filter_map { |a| normalize_author(a) }
|
|
42
|
+
picked = picked_contributor(slice['authors'], slice['contributor'])
|
|
43
|
+
picked ? slice['contributor'] = picked : slice.delete('contributor')
|
|
42
44
|
slice
|
|
43
45
|
end
|
|
44
46
|
|
|
47
|
+
# The contributor is one of the authors, so it is matched back against the
|
|
48
|
+
# saved author list and stored as that author. Anything that matches none
|
|
49
|
+
# of them — a stale pick whose author has since been removed, or a name
|
|
50
|
+
# that was never on the list — is dropped.
|
|
51
|
+
def picked_contributor(authors, contributor)
|
|
52
|
+
picked = normalize_author(contributor)
|
|
53
|
+
return nil if picked.nil?
|
|
54
|
+
|
|
55
|
+
authors.find { |author| same_person?(author, picked) }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# ORCID identifies a person when both sides carry one; otherwise fall back
|
|
59
|
+
# to the name pair, which is what the editor matches on too.
|
|
60
|
+
def same_person?(one, other)
|
|
61
|
+
orcids = [one, other].map { |a| a['orcid'].to_s.strip }
|
|
62
|
+
return orcids[0].casecmp?(orcids[1]) if orcids.all?(&:present?)
|
|
63
|
+
|
|
64
|
+
%w[givenName familyName].all? do |key|
|
|
65
|
+
one[key].to_s.strip.casecmp?(other[key].to_s.strip)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
45
69
|
def normalize_author(author)
|
|
46
70
|
return nil unless author.is_a?(Hash)
|
|
47
71
|
|
|
@@ -12,7 +12,7 @@ module Labimotion
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def self.elements_search(params, current_user, c_id, dl)
|
|
15
|
-
collection = Collection.
|
|
15
|
+
collection = Collection.belongs_to_or_shared_by(current_user.id, current_user.group_ids).find(c_id)
|
|
16
16
|
element_scope = Labimotion::Element.joins(:collections_elements).where('collections_elements.collection_id = ?', collection.id).joins(:element_klass).where('element_klasses.id = elements.element_klass_id AND element_klasses.name = ?', params[:selection][:genericElName])
|
|
17
17
|
element_scope = element_scope.where('elements.name like (?)', "%#{params[:selection][:searchName]}%") if params[:selection][:searchName].present?
|
|
18
18
|
element_scope = element_scope.where('elements.short_label like (?)', "%#{params[:selection][:searchShowLabel]}%") if params[:selection][:searchShowLabel].present?
|
|
@@ -97,7 +97,7 @@ module Labimotion
|
|
|
97
97
|
def self.samples_search(c_id = @c_id)
|
|
98
98
|
sqls = []
|
|
99
99
|
sps = params[:selection][:searchProperties]
|
|
100
|
-
collection = Collection.
|
|
100
|
+
collection = Collection.belongs_to_or_shared_by(current_user.id, current_user.group_ids).find(c_id)
|
|
101
101
|
element_scope = Sample.joins(:collections_samples).where('collections_samples.collection_id = ?', collection.id)
|
|
102
102
|
return element_scope if sps.empty?
|
|
103
103
|
|
data/lib/labimotion/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: labimotion
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.2.0.
|
|
4
|
+
version: 2.2.0.rc21
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chia-Lin Lin
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2026-07-
|
|
12
|
+
date: 2026-07-28 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: caxlsx
|