-
Notifications
You must be signed in to change notification settings - Fork 137
Expand file tree
/
Copy pathfile_sets_controller.rb
More file actions
404 lines (351 loc) · 13.9 KB
/
Copy pathfile_sets_controller.rb
File metadata and controls
404 lines (351 loc) · 13.9 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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
# frozen_string_literal: true
module Hyrax
class FileSetsController < ApplicationController
rescue_from WorkflowAuthorizationException, with: :render_unavailable
include Blacklight::Configurable
include Blacklight::SearchContext
include Blacklight::AccessControls::Catalog
include Hyrax::Breadcrumbs
include Hyrax::FlexibleSchemaBehavior if Hyrax.config.file_set_flexible?
include Hyrax::EnsureMigratedBehavior
before_action :authenticate_user!, except: [:show, :citation, :stats]
load_and_authorize_resource class: Hyrax.config.file_set_class
# If Hyrax.config.file_set_class is set to ::FileSet, the load above will force-cast
# the instance as a ::FileSet, even if it is a Hyrax::FileSet. Re-cast it back to
# prevent method errors and nil objects later
before_action :cast_file_set
before_action :build_breadcrumbs, only: [:show, :edit, :stats]
before_action :ensure_migrated_file_set, only: :edit
before_action do
blacklight_config.track_search_session = false
end
before_action :presenter
# provides the help_text view method
helper PermissionsHelper
helper_method :curation_concern
copy_blacklight_config_from(::CatalogController)
# Define collection specific filter facets.
configure_blacklight do |config|
config.search_builder_class = Hyrax::FileSetSearchBuilder
end
class_attribute :show_presenter, :form_class
self.show_presenter = Hyrax::FileSetPresenter
self.form_class = Hyrax::Forms::FileSetEditForm
# A little bit of explanation, CanCan(Can) sets the @file_set via the .load_and_authorize_resource
# method. However the interface for various CurationConcern modules leverages the #curation_concern method
# Thus we have file_set and curation_concern that are aliases for each other.
attr_accessor :file_set
alias curation_concern file_set
private :file_set=
alias curation_concern= file_set=
private :curation_concern=
helper_method :file_set
layout :decide_layout
# GET /concern/file_sets/:id
def edit
initialize_edit_form
end
# GET /concern/parent/:parent_id/file_sets/:id
def show
guard_for_workflow_restriction_on!(parent: parent(file_set: presenter))
respond_to do |wants|
wants.html
wants.json
additional_response_formats(wants)
end
end
# DELETE /concern/file_sets/:id
def destroy
guard_for_workflow_restriction_on!(parent: parent)
delete(file_set: curation_concern)
redirect_to [main_app, parent],
notice: view_context.t('hyrax.file_sets.asset_deleted_flash.message')
end
# PATCH /concern/file_sets/:id
def update
guard_for_workflow_restriction_on!(parent: parent)
if attempt_update
after_update_response
else
after_update_failure_response
end
rescue RSolr::Error::Http => error
flash[:error] = error.message
logger.error "FileSetsController::update rescued #{error.class}\n\t#{error.message}\n #{error.backtrace.join("\n")}\n\n"
render action: 'edit'
end
# GET /files/:id/stats
def stats
@stats = FileUsage.new(params[:id])
end
# GET /files/:id/citation
def citation; end
private
def ensure_migrated_file_set
# We need to know if a migration is going to happen, because if it is,
# we need to reset the memoized form.
needs_migration = wings_backed?(@file_set)
@file_set = ensure_migrated(
resource: @file_set,
transaction_key: 'change_set.update_file_set'
)
# If a migration happened, the memoized @form is now stale.
@form = nil if needs_migration
end
##
# @api public
def delete(file_set:)
case file_set
when Hyrax::Resource
transactions['file_set.destroy']
.with_step_args('file_set.remove_from_work' => { user: current_user },
'file_set.delete' => { user: current_user })
.call(curation_concern)
.value!
else
actor.destroy
end
end
##
# @api public
#
# @note this is provided so that implementing application can override this
# behavior and map params to different attributes
def update_metadata
case file_set
when Hyrax::Resource
valkyrie_update_metadata
else
file_attributes = form_class.model_attributes(attributes)
actor.update_metadata(file_attributes)
end
end
def valkyrie_update_metadata
change_set = Hyrax::Forms::ResourceForm.for(resource: file_set)
attributes = coerce_valkyrie_params
# TODO: We are not performing any error checks. So that's something to
# correct.
result =
change_set.validate(attributes) &&
transactions['change_set.update_file_set']
.with_step_args(
'file_set.save_acl' => { permissions_params: change_set.input_params["permissions"] }
)
.call(change_set).value_or { false }
@file_set = result if result
end
def coerce_valkyrie_params
attrs = attributes
# The HTML form might not submit the required data structure for reform;
# namely instead of a hash with positional arguments for nested attributes
# of a collection, it is an array. So we conditionally coerce that Array
# to a Hash.
# TODO: Do we need to concern ourself with embargo_attributes and
# lease_attributes? My suspicion is that since these are singular (for
# now), we don't. But it's a quick add.
[:permissions].each do |name|
next unless attrs["#{name}_attributes"].is_a?(Array)
new_perm_attrs = {}
attrs["#{name}_attributes"].each_with_index do |el, i|
new_perm_attrs[i] = el
end
attrs["#{name}_attributes"] = new_perm_attrs
end
attrs
end
def cast_file_set
return unless @file_set.class == ::FileSet
# We can tell if a Hyrax::FileSet was improperly cast because this AF method will
# return nil since its parent is not a ActiveFedora work.
@file_set = @file_set.valkyrie_resource if @file_set.respond_to?(:parent) && @file_set.parent&.id.nil?
end
def parent(file_set: curation_concern)
@parent ||=
case file_set
when Hyrax::Resource
# TODO: Add Hyrax::FileSet#parent method
Hyrax.query_service.find_parents(resource: file_set).first
else
file_set.parent
end
end
def attempt_update
return attempt_update_valkyrie if curation_concern.is_a?(Hyrax::Resource)
if wants_to_revert?
actor.revert_content(params[:revision])
elsif params.key?(:file_set)
if params[:file_set].key?(:files)
actor.update_content(uploaded_file_from_path)
else
update_metadata
end
elsif params.key?(:files_files) # version file already uploaded with ref id in :files_files array
uploaded_files = Array(Hyrax::UploadedFile.find(params[:files_files]))
actor.update_content(uploaded_files.first)
update_metadata
end
end
def attempt_update_valkyrie
return revert_valkyrie if wants_to_revert_valkyrie?
if params.key?(:file_set)
if params[:file_set].key?(:files)
ValkyrieIngestJob.perform_later(uploaded_file_from_path)
else
update_metadata
end
elsif params.key?(:files_files) # version file already uploaded with ref id in :files_files array
uploaded_files = Array(Hyrax::UploadedFile.find(params[:files_files]))
uploaded_files.first.file_set_uri = file_set.id.to_s
uploaded_files.first.save
ValkyrieIngestJob.perform_later(uploaded_files.first)
update_metadata
end
end
def revert_valkyrie
Hyrax::VersioningService.create(file_metadata, current_user, Hyrax.storage_adapter.find_by(id: params[:revision]))
# update_metadata
Hyrax.publisher.publish("file.uploaded", metadata: file_set.original_file)
true
end
def uploaded_file_from_path
# both storage backends accept the raw multipart upload object
Hyrax::UploadedFile.create(user_id: current_user.id,
file: params[:file_set][:files].first,
file_set_uri: @file_set.id.to_s)
end
def after_update_response
respond_to do |wants|
wants.html do
link_to_file = view_context.link_to(curation_concern, [main_app, curation_concern])
redirect_to [main_app, curation_concern], notice: view_context.t('hyrax.file_sets.asset_updated_flash.message', link_to_file: link_to_file)
end
wants.json do
@presenter = show_presenter.new(curation_concern, current_ability)
render :show, status: :ok, location: polymorphic_path([main_app, curation_concern])
end
end
end
def after_update_failure_response
respond_to do |wants|
wants.html do
initialize_edit_form
# TODO: return a valuable error message
flash[:error] = "There was a problem processing your request."
render 'edit', status: :unprocessable_entity
end
wants.json { render_json_response(response_type: :unprocessable_entity, options: { errors: curation_concern.errors }) }
end
end
def add_breadcrumb_for_controller
add_breadcrumb I18n.t('hyrax.dashboard.my.works'), hyrax.my_works_path
end
def add_breadcrumb_for_action
case action_name
when 'edit'
add_breadcrumb I18n.t("hyrax.file_set.browse_view"), main_app.hyrax_file_set_path(params["id"])
when 'show'
add_breadcrumb presenter.parent.to_s, main_app.polymorphic_path(presenter.parent) if presenter.parent.present?
add_breadcrumb presenter.to_s, main_app.polymorphic_path(presenter)
end
end
def initialize_edit_form
guard_for_workflow_restriction_on!(parent: parent)
case file_set
when Hyrax::Resource
@form = Hyrax::Forms::ResourceForm.for(resource: file_set)
@form.prepopulate!
else
@form = form_class.new(file_set)
end
@version_list = Hyrax::VersionListPresenter.for(file_set: file_set)
@groups = current_user.groups
end
include WorkflowsHelper # Provides #workflow_restriction?, and yes I mean include not helper; helper exposes the module methods
# @param parent [Hyrax::WorkShowPresenter, GenericWork, #suppressed?] an
# object on which we check if the current can take action.
#
# @return true if we did not encounter any workflow restrictions
# @raise WorkflowAuthorizationException if we encountered some workflow_restriction
def guard_for_workflow_restriction_on!(parent:)
return true unless workflow_restriction?(parent, ability: current_ability)
raise WorkflowAuthorizationException
end
def actor
@actor ||= Hyrax::Actors::FileSetActor.new(@file_set, current_user)
end
def attributes
params.fetch(:file_set, {}).except(:files).permit!.dup # use a copy of the hash so that original params stays untouched when interpret_visibility modifies things
end
def presenter
@presenter ||= begin
presenter = show_presenter.new(curation_concern_document, current_ability, request)
raise WorkflowAuthorizationException if presenter.parent.blank?
presenter
end
end
def curation_concern_document
# Query Solr for the collection.
# run the solr query to find the collection members
response, _docs = single_item_search_service.search_results
curation_concern = response.documents.first
raise CanCan::AccessDenied unless curation_concern
curation_concern
end
def single_item_search_service
Hyrax::SearchService.new(config: blacklight_config, user_params: params.except(:q, :page), scope: self, search_builder_class: blacklight_config.search_builder_class)
end
def wants_to_revert?
params.key?(:revision) && params[:revision] != curation_concern.latest_content_version.label
end
def wants_to_revert_valkyrie?
params.key?(:revision) && params[:revision] != Hyrax::VersioningService.new(resource: file_metadata).latest_version.version_id.to_s
end
def file_metadata
@file_metadata ||= Hyrax.config.file_set_file_service.primary_file_for(file_set: file_set)
end
# Override this method to add additional response formats to your local app
def additional_response_formats(_); end
# This allows us to use the unauthorized and form_permission template in hyrax/base,
# while prefering our local paths. Thus we are unable to just override `self.local_prefixes`
def _prefixes
@_prefixes ||= super + ['hyrax/base']
end
def decide_layout
layout = case action_name
when 'show'
'1_column'
else
'dashboard'
end
File.join(theme, layout)
end
# rubocop:disable Metrics/MethodLength
def render_unavailable
message = I18n.t("hyrax.workflow.unauthorized_parent")
respond_to do |wants|
wants.html do
unavailable_presenter
flash[:notice] = message
render 'unavailable', status: :unauthorized
end
wants.json do
render plain: message, status: :unauthorized
end
additional_response_formats(wants)
wants.ttl do
render plain: message, status: :unauthorized
end
wants.jsonld do
render plain: message, status: :unauthorized
end
wants.nt do
render plain: message, status: :unauthorized
end
end
end
# rubocop:enable Metrics/MethodLength
def unavailable_presenter
@presenter ||= show_presenter.new(::SolrDocument.find(params[:id]), current_ability, request)
end
end
end