-
Notifications
You must be signed in to change notification settings - Fork 118
Expand file tree
/
Copy pathorgs_controller.rb
More file actions
286 lines (247 loc) · 10.5 KB
/
orgs_controller.rb
File metadata and controls
286 lines (247 loc) · 10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# frozen_string_literal: true
# Controller for Org pages for Admins
class OrgsController < ApplicationController
include OrgSelectable
after_action :verify_authorized, except: %w[
shibboleth_ds shibboleth_ds_passthru search
]
respond_to :html
# TODO: Refactor this one along with super_admin/orgs_controller. Consider moving
# to a new `admin` namespace, leaving public facing actions in here and
# moving all of the `admin_` ones to the `admin` namespaced controller
# TODO: Just use instance variables instead of passing locals. Separating the
# create/update will make that easier.
# GET /org/admin/:id/admin_edit
def admin_edit
org = Org.find(params[:id])
authorize org
languages = Language.all.order('name')
org.links = { org: [] } unless org.links.present?
render 'admin_edit', locals: { org: org, languages: languages, method: 'PUT',
url: admin_update_org_path(org) }
end
# PUT /org/admin/:id/admin_update
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
def admin_update
attrs = org_params
@org = Org.find(params[:id])
authorize @org
attrs = handle_logo(attrs)
tab = (attrs[:feedback_enabled].present? ? 'feedback' : 'profile')
@org.links = ActiveSupport::JSON.decode(params[:org_links]) if params[:org_links].present?
# Only allow super admins to change the org types and shib info
if current_user.can_super_admin?
attrs = handle_managed_flag(attrs)
attrs = handle_shibboleth_identifier(attrs)
identifiers = []
# See if the user selected a new Org via the Org Lookup and
# convert it into an Org
lookup = org_from_params(params_in: attrs)
ids = identifiers_from_params(params_in: attrs)
identifiers += ids.select { |id| id.value.present? }
end
# Remove the extraneous Org Selector hidden fields
attrs = remove_org_selection_params(params_in: attrs)
if @org.update(attrs)
# Save any identifiers that were found
if current_user.can_super_admin? && lookup.present?
# Loop through the identifiers and then replace the existing
# identifier and save the new one
identifiers.each do |id|
@org = process_identifier_change(org: @org, identifier: id)
end
@org.save
end
redirect_to "#{admin_edit_org_path(@org)}##{tab}",
notice: success_message(@org, _('saved'))
else
failure = failure_message(@org, _('save')) if failure.blank?
redirect_to "#{admin_edit_org_path(@org)}##{tab}", alert: failure
end
end
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
# This action is used by installations that have the following config enabled:
# Rails.configuration.x.shibboleth.use_filtered_discovery_service
# rubocop:disable Metrics/AbcSize
def shibboleth_ds
unless current_user.nil?
redirect_to root_path
return
end
@user = User.new
# Display the custom Shibboleth discovery service page.
@orgs = Identifier.by_scheme_name('shibboleth', 'Org')
.sort { |a, b| a.identifiable.name <=> b.identifiable.name }
.map(&:identifiable)
# Disabling the rubocop check here because it would not be clear what happens
# if the ``@orgs` array has items ... it renders the shibboleth_ds view
# rubocop:disable Style/GuardClause, Style/RedundantReturn
if @orgs.empty?
flash.now[:alert] = _('No organisations are currently registered.')
redirect_to user_shibboleth_omniauth_authorize_path
return
end
# rubocop:enable Style/GuardClause, Style/RedundantReturn
end
# This action is used to redirect a user to the Shibboleth IdP
# POST /orgs/shibboleth_ds
def shibboleth_ds_passthru
if shib_params[:org_id].blank?
redirect_to shibboleth_ds_path, notice: _('Please choose an organisation')
else
session['org_id'] = shib_params[:org_id]
org = Org.where(id: shib_params[:org_id])
shib_entity = Identifier.by_scheme_name('shibboleth', 'Org')
.where(identifiable: org)
if shib_entity.empty?
failure = _('Your organisation does not seem to be properly configured.')
redirect_to shibboleth_ds_path, alert: failure
else
# initiate shibboleth login sequence
entity_param = "entityID=#{shib_entity.first.value}"
redirect_to "#{shib_login_url}?#{shib_callback_url}&#{entity_param}"
end
end
end
# rubocop:enable Metrics/AbcSize
# POST /orgs (via AJAX from Org Typeaheads ... see below for specific pages)
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
def search
args = search_params
# If the search term is greater than 2 characters
if args.present? && args.fetch(:name, '').length > 2
type = params.fetch(:type, 'local')
# If we are including external API results
orgs = case type
when 'combined'
# This type will search both ROR and the local DB giving the local
# DB results preference. It is triggered from the following pages:
# Create Account
# Edit Profile
# Admin Edit User
# Contributor Edit/New
# Project Details (Funder selection)
#
# Those pages use the app/views/shared/org_selectors/_combined.html.erb
OrgSelection::SearchService.search_combined(
search_term: args[:name]
)
when 'external'
# This type will ONLY check ROR for the specified search term. It
# is triggered from the following page:
# SuperAdmin - New Org
#
# That page uses the app/views/shared/org_selectors/_external_only.html.erb
OrgSelection::SearchService.search_externally(
search_term: args[:name]
)
else
# This default will ONLY check the local DB's Org table. It is
# currently not triggered by any pages.
OrgSelection::SearchService.search_locally(
search_term: args[:name]
)
end
# Scenarios where we only allow the user to select from the Orgs in the
# local DB use the app/views/shared/org_selectors/_local_only.html.erb
# which is not AJAX. The page has the entire list of Orgs and so does not
# call this #search action!
# The following pages currently have this behavior:
# Create Plan page (both Research Org and Funder typeaheads)
# Templates page (SuperAdmin Org Affiliation change)
# If we need to restrict the results to funding orgs then
# only return the ones with a valid fundref
if orgs.present? && params.fetch(:funder_only, 'false') == 'true'
orgs = orgs.select do |org|
org[:fundref].present? && !org[:fundref].blank?
end
end
render json: orgs
else
render json: []
end
end
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
private
def org_params
params.require(:org)
.permit(:name, :abbreviation, :logo, :contact_email, :contact_name,
:remove_logo, :managed, :feedback_enabled, :org_links,
:funder, :institution, :organisation,
:feedback_msg, :org_id, :org_name, :org_crosswalk,
:helpdesk_email,
identifiers_attributes: %i[identifier_scheme_id value],
tracker_attributes: %i[code id])
end
def shib_params
params.permit('org_id')
end
def search_params
params.require(:org).permit(:name, :type)
end
def handle_logo(attrs)
# If a new logo was supplied then use it, otherwise retain the existing one
attrs[:logo] = attrs[:logo].present? ? attrs[:logo] : @org.logo
# Remove the logo if the user checked the box
attrs[:logo] = nil if attrs[:remove_logo] == '1'
attrs
end
def handle_managed_flag(attrs)
# NOTE: `:managed` is controlled by a check_box in the form
# `app/views/orgs/_profile_form.html.erb`.
attrs[:managed] = (attrs[:managed] == '1') if attrs.key?(:managed)
attrs
end
# Updates the @org's Shibboleth identifier(s) if the required conditions are met
# rubocop:disable Metrics/AbcSize
def handle_shibboleth_identifier(attrs)
return attrs unless Rails.configuration.x.shibboleth.use_filtered_discovery_service
shib = IdentifierScheme.by_name('shibboleth').first
if shib.present? && attrs[:identifiers_attributes].present?
key = attrs[:identifiers_attributes].keys.first
entity_id = attrs[:identifiers_attributes][:"#{key}"][:value]
if entity_id.present?
identifier = Identifier.find_or_initialize_by(
identifiable: @org, identifier_scheme: shib, value: entity_id
)
@org = process_identifier_change(org: @org, identifier: identifier)
else
# The user blanked out the entityID so delete the record
@org.identifier_for_scheme(scheme: shib)&.destroy
end
end
attrs.delete(:identifiers_attributes)
attrs
end
# rubocop:enable Metrics/AbcSize
def shib_login_url
shib_login = Rails.configuration.x.shibboleth.login_url
"#{request.base_url.gsub('http:', 'https:')}#{shib_login}"
end
def shib_callback_url
"target=#{user_shibboleth_omniauth_callback_url.gsub('http:', 'https:')}"
end
# Destroy the identifier if it exists and was blanked out, replace the
# identifier if it was updated, create the identifier if its new, or
# ignore it
# rubocop:disable Metrics/AbcSize
def process_identifier_change(org:, identifier:)
return org unless identifier.is_a?(Identifier)
if !identifier.new_record? && identifier.value.blank?
# Remove the identifier if it has been blanked out
identifier.destroy
elsif identifier.value.present?
# If the identifier already exists then remove it
current = org.identifier_for_scheme(scheme: identifier.identifier_scheme)
current.destroy if current.present? && current.value != identifier.value
identifier.identifiable = org
org.identifiers << identifier
end
org
end
# rubocop:enable Metrics/AbcSize
end