1
+ # frozen_string_literal: true
2
+
3
+ module Nova
4
+ # Controller for the Contributors page
5
+ class ContributorsController < ApplicationController
6
+ include OrgSelectable
7
+ helper PaginableHelper
8
+
9
+ before_action :fetch_plan
10
+ before_action :fetch_contributor , only : %i[ edit update destroy ]
11
+ after_action :verify_authorized
12
+
13
+ # GET /plans/:plan_id/contributors
14
+ def index
15
+ authorize @plan , :show?
16
+ @contributors = @plan . contributors
17
+ end
18
+
19
+ # GET /plans/:plan_id/contributors/new
20
+ def new
21
+ authorize @plan
22
+ default_org = @plan . org . present? ? @plan . org : current_user . org
23
+ @contributor = Contributor . new ( plan : @plan , org : default_org )
24
+ end
25
+
26
+ # GET /plans/:plan_id/contributors/:id/edit
27
+ def edit
28
+ authorize @plan
29
+ end
30
+
31
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
32
+ # POST /plans/:plan_id/contributors
33
+ def create
34
+ authorize @plan , :edit?
35
+
36
+ args = translate_roles ( hash : contributor_params )
37
+ args = process_org ( hash : args )
38
+ if args . blank?
39
+ @contributor = Contributor . new ( args )
40
+ @contributor . errors . add ( :affiliation , 'invalid' )
41
+ flash [ :alert ] = failure_message ( @contributor , _ ( 'add' ) )
42
+ render :new
43
+ else
44
+ args = process_orcid_for_create ( hash : args )
45
+
46
+ # Check if ORCID exists and validate using the orcid_validator class method
47
+ if args [ :identifiers_attributes ] . present?
48
+ orcid_value = args [ :identifiers_attributes ] [ :'0' ] [ :value ]
49
+ orcid_id = OrcidValidator . extract_orcid_id ( orcid_value )
50
+
51
+ unless orcid_id && OrcidValidator . orcid_id_is_valid? ( orcid_id )
52
+ @contributor = Contributor . new ( args )
53
+ @contributor . errors . add ( :base , 'ORCID iD is invalid' )
54
+ flash [ :alert ] = failure_message ( @contributor , _ ( 'add' ) )
55
+ render :new
56
+ return
57
+ end
58
+ end
59
+
60
+ args [ :plan_id ] = @plan . id
61
+ @contributor = Contributor . new ( args )
62
+ stash_orcid
63
+
64
+ if @contributor . save
65
+ # Now that the model has been ssaved, go ahead and save the identifiers
66
+ save_orcid
67
+ redirect_to plan_contributors_path ( @plan ) ,
68
+ notice : success_message ( @contributor , _ ( 'added' ) )
69
+ else
70
+ flash [ :alert ] = failure_message ( @contributor , _ ( 'add' ) )
71
+ render :new
72
+ end
73
+ end
74
+ end
75
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
76
+
77
+ # PUT /plans/:plan_id/contributors/:id
78
+ def update
79
+ authorize @plan
80
+ args = translate_roles ( hash : contributor_params )
81
+ args = process_org ( hash : args )
82
+ args = process_orcid_for_update ( hash : args )
83
+
84
+ # Check if ORCID exists and validate using the orcid_validator class method
85
+ if args [ :identifiers_attributes ] . present?
86
+ orcid_value = args [ :identifiers_attributes ] [ :'0' ] [ :value ]
87
+ orcid_id = OrcidValidator . extract_orcid_id ( orcid_value )
88
+
89
+ unless orcid_id && OrcidValidator . orcid_id_is_valid? ( orcid_id )
90
+ @contributor = Contributor . new ( args )
91
+ @contributor . errors . add ( :base , 'ORCID iD is invalid' )
92
+ flash [ :alert ] = failure_message ( @contributor , _ ( 'add' ) )
93
+ render :new
94
+ return
95
+ end
96
+ end
97
+
98
+ if @contributor . update ( args )
99
+ redirect_to edit_plan_contributor_path ( @plan , @contributor ) ,
100
+ notice : success_message ( @contributor , _ ( 'saved' ) )
101
+ else
102
+ flash . now [ :alert ] = failure_message ( @contributor , _ ( 'save' ) )
103
+ render :edit
104
+ end
105
+ end
106
+ # rubocop:enable
107
+
108
+ # DELETE /plans/:plan_id/contributors/:id
109
+ def destroy
110
+ authorize @plan
111
+ if @contributor . destroy
112
+ msg = success_message ( @contributor , _ ( 'removed' ) )
113
+ redirect_to plan_contributors_path ( @plan ) , notice : msg
114
+ else
115
+ flash . now [ :alert ] = failure_message ( @contributor , _ ( 'remove' ) )
116
+ render :edit
117
+ end
118
+ end
119
+
120
+ private
121
+
122
+ def contributor_params
123
+ base_params = %i[ name email phone org_id org_name org_crosswalk ]
124
+ role_params = Contributor . new . all_roles
125
+
126
+ params . require ( :contributor ) . permit (
127
+ base_params ,
128
+ role_params ,
129
+ identifiers_attributes : %i[ id identifier_scheme_id value attrs ]
130
+ )
131
+ end
132
+
133
+ # Translate the check boxes values of "1" and "0" to true/false
134
+ def translate_roles ( hash :)
135
+ roles = Contributor . new . all_roles
136
+ roles . each { |role | hash [ role . to_sym ] = hash [ role . to_sym ] == '1' }
137
+ hash
138
+ end
139
+
140
+ # Convert the Org Hash into an Org object (creating it if allowed)
141
+ # and then remove all of the Org args
142
+ def process_org ( hash :)
143
+ return hash unless hash . present? && hash [ :org_id ] . present?
144
+
145
+ allow = !Rails . configuration . x . application . restrict_orgs
146
+ org = org_from_params ( params_in : hash ,
147
+ allow_create : allow )
148
+
149
+ hash = remove_org_selection_params ( params_in : hash )
150
+
151
+ return hash if org . blank? && !allow
152
+ return hash unless org . present?
153
+
154
+ hash [ :org_id ] = org . id
155
+ hash
156
+ end
157
+
158
+ # When creating, just remove the ORCID if it was left blank
159
+ def process_orcid_for_create ( hash :)
160
+ return hash unless hash [ :identifiers_attributes ] . present?
161
+
162
+ id_hash = hash [ :identifiers_attributes ] [ :'0' ]
163
+ return hash unless id_hash [ :value ] . blank?
164
+
165
+ hash . delete ( :identifiers_attributes )
166
+ hash
167
+ end
168
+
169
+ # When updating, destroy the ORCID if it was blanked out on form
170
+ def process_orcid_for_update ( hash :)
171
+ return hash unless hash [ :identifiers_attributes ] . present?
172
+
173
+ id_hash = hash [ :identifiers_attributes ] [ :'0' ]
174
+ return hash unless id_hash [ :value ] . blank?
175
+
176
+ existing = @contributor . identifier_for_scheme ( scheme : 'orcid' )
177
+ existing . destroy if existing . present?
178
+ hash . delete ( :identifiers_attributes )
179
+ hash
180
+ end
181
+
182
+ # =============
183
+ # = Callbacks =
184
+ # =============
185
+ def fetch_plan
186
+ @plan = Plan . find_by ( id : params [ :plan_id ] )
187
+ return true if @plan . present?
188
+
189
+ redirect_to root_path , alert : _ ( 'plan not found' )
190
+ end
191
+
192
+ def fetch_contributor
193
+ @contributor = Contributor . find_by ( id : params [ :id ] )
194
+ return true if @contributor . present? &&
195
+ @plan . contributors . include? ( @contributor )
196
+
197
+ redirect_to plan_contributors_path , alert : _ ( 'contributor not found' )
198
+ end
199
+
200
+ # The following 2 methods address an issue with using Rails normal
201
+ # accepts_nested_attributes_for on polymorphic relationships.
202
+ #
203
+ # Currently, when creating the underlying model, the `.valid?` method is
204
+ # called prior to the `save`. This causes all `identifiers` to report that
205
+ # the `identifiable_id` is nil. Because Rails forces the `belong_to` relation
206
+ # to be present.
207
+ #
208
+ # To get around it we stash the identifiers during the creation step
209
+ # and then save them after the model has been created
210
+ #
211
+ # Supposedly this is fixed in Rails 5+ by designating `optional: true`
212
+ # on the `belong_to` side of the relationship
213
+ def stash_orcid
214
+ return false unless @contributor . identifiers . any?
215
+
216
+ @cached_orcid = @contributor . identifiers . first
217
+ @contributor . identifiers = [ ]
218
+ end
219
+
220
+ def save_orcid
221
+ return true unless @cached_orcid . present?
222
+
223
+ @cached_orcid . identifiable = @contributor
224
+ @cached_orcid . save
225
+ @contributor . reload
226
+ end
227
+ end
228
+ end
0 commit comments