curation_concerns 1.7.3 → 1.7.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/actors/curation_concerns/optimistic_lock_validator.rb +28 -0
- data/app/assets/javascripts/curation_concerns/file_manager/sorting.es6 +17 -7
- data/app/controllers/concerns/curation_concerns/curation_concern_controller.rb +6 -1
- data/app/forms/curation_concerns/forms/file_manager_form.rb +27 -0
- data/app/forms/curation_concerns/forms/work_form.rb +8 -0
- data/app/models/concerns/curation_concerns/ability.rb +1 -0
- data/app/models/concerns/curation_concerns/work_behavior.rb +6 -0
- data/app/presenters/curation_concerns/member_presenter_factory.rb +70 -0
- data/app/presenters/curation_concerns/work_show_presenter.rb +7 -53
- data/app/services/curation_concerns/actors/actor_factory.rb +2 -1
- data/app/views/curation_concerns/base/_file_manager_member_resource_options.html.erb +2 -2
- data/app/views/curation_concerns/base/_file_manager_members.html.erb +13 -5
- data/app/views/curation_concerns/base/_file_manager_resource_form.html.erb +1 -1
- data/app/views/curation_concerns/base/_form.html.erb +3 -0
- data/app/views/curation_concerns/base/file_manager.html.erb +2 -2
- data/app/views/curation_concerns/base/show.json.jbuilder +2 -1
- data/config/locales/curation_concerns.en.yml +4 -0
- data/lib/curation_concerns/version.rb +1 -1
- data/spec/actors/curation_concerns/optimistic_lock_validator_spec.rb +50 -0
- data/spec/controllers/curation_concerns/generic_works_controller_spec.rb +1 -1
- data/spec/forms/work_form_spec.rb +8 -0
- data/spec/presenters/curation_concerns/member_presenter_factory_spec.rb +25 -0
- data/spec/presenters/curation_concerns/work_show_presenter_spec.rb +1 -21
- data/spec/views/curation_concerns/base/_form.html.erb_spec.rb +35 -0
- data/spec/views/curation_concerns/base/file_manager.html.erb_spec.rb +10 -8
- data/spec/views/curation_concerns/base/show.json.jbuilder_spec.rb +3 -1
- metadata +12 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0264d3ffe1409c035fd9849f11c7ade0dc92c3c1
|
4
|
+
data.tar.gz: 912f6765b87b3ebe922ccc17ea4689925fe03acb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24a1f4ca059a85819570ea0d2df252ab03e340fccb56e33d342f9af452272d60ac43677adb4b5aa374391fc07b01b36c3b30b060739941bc64c66294937dc2aa
|
7
|
+
data.tar.gz: a8ecc0679718f7c9f4f9e942c0fd2d97a25564a085e6bf7e5f6c1daf0714348a2ca95627af4218f61ea633dc8f4535ebc01fc83f5e8b05a560fa8fe71515691d
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module CurationConcerns
|
2
|
+
# Validates that the submitted version is the most recent version in the datastore.
|
3
|
+
# Caveat: we are not detecting if the version is changed by a different process between
|
4
|
+
# the time this validator is run and when the object is saved
|
5
|
+
class OptimisticLockValidator < Actors::AbstractActor
|
6
|
+
class_attribute :version_field
|
7
|
+
self.version_field = 'version'
|
8
|
+
|
9
|
+
def update(attributes)
|
10
|
+
validate_lock(version_attribute(attributes)) && next_actor.update(attributes)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# @return [Boolean] returns true if the lock is missing or
|
16
|
+
# if it matches the current object version.
|
17
|
+
def validate_lock(version)
|
18
|
+
return true if version.blank? || version == curation_concern.etag
|
19
|
+
curation_concern.errors.add(:base, :conflict)
|
20
|
+
false
|
21
|
+
end
|
22
|
+
|
23
|
+
# Removes the version attribute
|
24
|
+
def version_attribute(attributes)
|
25
|
+
attributes.delete(version_field)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -15,18 +15,14 @@ export default class SortManager {
|
|
15
15
|
}
|
16
16
|
|
17
17
|
persist() {
|
18
|
-
let params = {}
|
19
|
-
params[this.singular_class_name] = {
|
20
|
-
"ordered_member_ids": this.order
|
21
|
-
}
|
22
|
-
params["_method"] = "PATCH"
|
23
18
|
this.element.addClass("pending")
|
24
19
|
this.element.removeClass("success")
|
25
20
|
this.element.removeClass("failure")
|
26
21
|
let persisting = $.post(
|
27
22
|
`/concern/${this.class_name}/${this.id}.json`,
|
28
|
-
params
|
29
|
-
).done(() => {
|
23
|
+
this.params()
|
24
|
+
).done((response) => {
|
25
|
+
this.element.data('version', response.version)
|
30
26
|
this.element.data("current-order", this.order)
|
31
27
|
this.element.addClass("success")
|
32
28
|
this.element.removeClass("failure")
|
@@ -39,6 +35,16 @@ export default class SortManager {
|
|
39
35
|
return persisting
|
40
36
|
}
|
41
37
|
|
38
|
+
params() {
|
39
|
+
let params = {}
|
40
|
+
params[this.singular_class_name] = {
|
41
|
+
"version": this.version,
|
42
|
+
"ordered_member_ids": this.order
|
43
|
+
}
|
44
|
+
params["_method"] = "PATCH"
|
45
|
+
return params
|
46
|
+
}
|
47
|
+
|
42
48
|
get_sort_position(item) {
|
43
49
|
return this.element.children().index(item)
|
44
50
|
}
|
@@ -88,6 +94,10 @@ export default class SortManager {
|
|
88
94
|
).toArray()
|
89
95
|
}
|
90
96
|
|
97
|
+
get version() {
|
98
|
+
return this.element.data('version')
|
99
|
+
}
|
100
|
+
|
91
101
|
get alpha_sort_button() {
|
92
102
|
return $("*[data-action='alpha-sort-action']")
|
93
103
|
}
|
@@ -22,6 +22,11 @@ module CurationConcerns
|
|
22
22
|
module ClassMethods
|
23
23
|
def curation_concern_type=(curation_concern_type)
|
24
24
|
load_and_authorize_resource class: curation_concern_type, instance_name: :curation_concern, except: [:show, :file_manager, :inspect_work]
|
25
|
+
|
26
|
+
# Load the fedora resource to get the etag.
|
27
|
+
# No need to authorize for the file manager, because it does authorization via the presenter.
|
28
|
+
load_resource class: curation_concern_type, instance_name: :curation_concern, only: :file_manager
|
29
|
+
|
25
30
|
self._curation_concern_type = curation_concern_type
|
26
31
|
end
|
27
32
|
|
@@ -104,7 +109,7 @@ module CurationConcerns
|
|
104
109
|
end
|
105
110
|
|
106
111
|
def file_manager
|
107
|
-
|
112
|
+
@form = Forms::FileManagerForm.new(curation_concern, current_ability)
|
108
113
|
end
|
109
114
|
|
110
115
|
def inspect_work
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module CurationConcerns
|
2
|
+
module Forms
|
3
|
+
class FileManagerForm
|
4
|
+
include HydraEditor::Form
|
5
|
+
self.terms = []
|
6
|
+
delegate :id, :thumbnail_id, :representative_id, :to_s, to: :model
|
7
|
+
attr_reader :current_ability, :request
|
8
|
+
def initialize(work, ability)
|
9
|
+
super(work)
|
10
|
+
@current_ability = ability
|
11
|
+
@request = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def version
|
15
|
+
model.etag
|
16
|
+
end
|
17
|
+
|
18
|
+
delegate :member_presenters, to: :member_presenter_factory
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def member_presenter_factory
|
23
|
+
MemberPresenterFactory.new(work, ability)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -26,6 +26,10 @@ module CurationConcerns
|
|
26
26
|
super(model)
|
27
27
|
end
|
28
28
|
|
29
|
+
def version
|
30
|
+
model.etag
|
31
|
+
end
|
32
|
+
|
29
33
|
# The value for embargo_relase_date and lease_expiration_date should not
|
30
34
|
# be initialized to empty string
|
31
35
|
def initialize_field(key)
|
@@ -51,6 +55,10 @@ module CurationConcerns
|
|
51
55
|
super
|
52
56
|
end
|
53
57
|
end
|
58
|
+
|
59
|
+
def build_permitted_params
|
60
|
+
super + [:version]
|
61
|
+
end
|
54
62
|
end
|
55
63
|
|
56
64
|
private
|
@@ -24,6 +24,12 @@ module CurationConcerns::WorkBehavior
|
|
24
24
|
self.indexer = CurationConcerns::WorkIndexer
|
25
25
|
end
|
26
26
|
|
27
|
+
# TODO: Move this into ActiveFedora
|
28
|
+
def etag
|
29
|
+
raise "Unable to produce an etag for a unsaved object" unless persisted?
|
30
|
+
ldp_source.head.etag
|
31
|
+
end
|
32
|
+
|
27
33
|
module ClassMethods
|
28
34
|
# This governs which partial to draw when you render this type of object
|
29
35
|
def _to_partial_path #:nodoc:
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module CurationConcerns
|
2
|
+
# Creates the presenters of the members (member works and file sets) of a specific object
|
3
|
+
class MemberPresenterFactory
|
4
|
+
class_attribute :file_presenter_class, :work_presenter_class
|
5
|
+
# modify this attribute to use an alternate presenter class for the files
|
6
|
+
self.file_presenter_class = FileSetPresenter
|
7
|
+
|
8
|
+
# modify this attribute to use an alternate presenter class for the child works
|
9
|
+
self.work_presenter_class = WorkShowPresenter
|
10
|
+
|
11
|
+
def initialize(work, ability, request = nil)
|
12
|
+
@work = work
|
13
|
+
@current_ability = ability
|
14
|
+
@request = request
|
15
|
+
end
|
16
|
+
|
17
|
+
delegate :id, to: :@work
|
18
|
+
attr_reader :current_ability, :request
|
19
|
+
|
20
|
+
# @param [Array<String>] ids a list of ids to build presenters for
|
21
|
+
# @param [Class] presenter_class the type of presenter to build
|
22
|
+
# @return [Array<presenter_class>] presenters for the ordered_members (not filtered by class)
|
23
|
+
def member_presenters(ids = ordered_ids, presenter_class = composite_presenter_class)
|
24
|
+
PresenterFactory.build_presenters(ids, presenter_class, *presenter_factory_arguments)
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [Array<FileSetPresenter>] presenters for the orderd_members that are FileSets
|
28
|
+
def file_set_presenters
|
29
|
+
@file_set_presenters ||= member_presenters(ordered_ids & file_set_ids)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [Array<WorkShowPresenter>] presenters for the ordered_members that are not FileSets
|
33
|
+
def work_presenters
|
34
|
+
@work_presenters ||= member_presenters(ordered_ids - file_set_ids, work_presenter_class)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# TODO: Extract this to ActiveFedora::Aggregations::ListSource
|
40
|
+
def ordered_ids
|
41
|
+
@ordered_ids ||= begin
|
42
|
+
ActiveFedora::SolrService.query("proxy_in_ssi:#{id}",
|
43
|
+
rows: 10_000,
|
44
|
+
fl: "ordered_targets_ssim")
|
45
|
+
.flat_map { |x| x.fetch("ordered_targets_ssim", []) }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# These are the file sets that belong to this work, but not necessarily
|
50
|
+
# in order.
|
51
|
+
# Arbitrarily maxed at 10 thousand; had to specify rows due to solr's default of 10
|
52
|
+
def file_set_ids
|
53
|
+
@file_set_ids ||= begin
|
54
|
+
ActiveFedora::SolrService.query("{!field f=has_model_ssim}FileSet",
|
55
|
+
rows: 10_000,
|
56
|
+
fl: ActiveFedora.id_field,
|
57
|
+
fq: "{!join from=ordered_targets_ssim to=id}id:\"#{id}/list_source\"")
|
58
|
+
.flat_map { |x| x.fetch(ActiveFedora.id_field, []) }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def presenter_factory_arguments
|
63
|
+
[current_ability, request]
|
64
|
+
end
|
65
|
+
|
66
|
+
def composite_presenter_class
|
67
|
+
CompositePresenterFactory.new(file_presenter_class, work_presenter_class, ordered_ids & file_set_ids)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -4,17 +4,11 @@ module CurationConcerns
|
|
4
4
|
include PresentsAttributes
|
5
5
|
attr_accessor :solr_document, :current_ability, :request
|
6
6
|
|
7
|
-
class_attribute :collection_presenter_class
|
7
|
+
class_attribute :collection_presenter_class
|
8
8
|
|
9
9
|
# modify this attribute to use an alternate presenter class for the collections
|
10
10
|
self.collection_presenter_class = CollectionPresenter
|
11
11
|
|
12
|
-
# modify this attribute to use an alternate presenter class for the files
|
13
|
-
self.file_presenter_class = FileSetPresenter
|
14
|
-
|
15
|
-
# modify this attribute to use an alternate presenter class for the child works
|
16
|
-
self.work_presenter_class = self
|
17
|
-
|
18
12
|
# Methods used by blacklight helpers
|
19
13
|
delegate :has?, :first, :fetch, :export_formats, :export_as, to: :solr_document
|
20
14
|
|
@@ -41,11 +35,6 @@ module CurationConcerns
|
|
41
35
|
:lease_expiration_date, :rights, :source, :thumbnail_id, :representative_id,
|
42
36
|
to: :solr_document
|
43
37
|
|
44
|
-
# @return [Array<FileSetPresenter>] presenters for the orderd_members that are FileSets
|
45
|
-
def file_set_presenters
|
46
|
-
@file_set_presenters ||= member_presenters(ordered_ids & file_set_ids)
|
47
|
-
end
|
48
|
-
|
49
38
|
def workflow
|
50
39
|
@workflow ||= WorkflowPresenter.new(solr_document, current_ability)
|
51
40
|
end
|
@@ -68,24 +57,6 @@ module CurationConcerns
|
|
68
57
|
end
|
69
58
|
end
|
70
59
|
|
71
|
-
# @return [Array<WorkShowPresenter>] presenters for the ordered_members that are not FileSets
|
72
|
-
def work_presenters
|
73
|
-
@work_presenters ||= member_presenters(ordered_ids - file_set_ids, work_presenter_class)
|
74
|
-
end
|
75
|
-
|
76
|
-
# @param [Array<String>] ids a list of ids to build presenters for
|
77
|
-
# @param [Class] presenter_class the type of presenter to build
|
78
|
-
# @return [Array<presenter_class>] presenters for the ordered_members (not filtered by class)
|
79
|
-
def member_presenters(ids = ordered_ids, presenter_class = composite_presenter_class)
|
80
|
-
PresenterFactory.build_presenters(ids,
|
81
|
-
presenter_class,
|
82
|
-
*presenter_factory_arguments)
|
83
|
-
end
|
84
|
-
|
85
|
-
def composite_presenter_class
|
86
|
-
CompositePresenterFactory.new(file_presenter_class, work_presenter_class, ordered_ids & file_set_ids)
|
87
|
-
end
|
88
|
-
|
89
60
|
# @return [Array<CollectionPresenter>] presenters for the collections that this work is a member of
|
90
61
|
def collection_presenters
|
91
62
|
PresenterFactory.build_presenters(in_collection_ids,
|
@@ -109,11 +80,9 @@ module CurationConcerns
|
|
109
80
|
graph.dump(:ttl)
|
110
81
|
end
|
111
82
|
|
112
|
-
|
83
|
+
delegate :member_presenters, :file_set_presenters, :work_presenters, to: :member_presenter_factory
|
113
84
|
|
114
|
-
|
115
|
-
GraphExporter.new(solr_document, request).fetch
|
116
|
-
end
|
85
|
+
private
|
117
86
|
|
118
87
|
def presenter_factory_arguments
|
119
88
|
[current_ability, request]
|
@@ -126,27 +95,12 @@ module CurationConcerns
|
|
126
95
|
.map { |x| x.fetch(ActiveFedora.id_field) }
|
127
96
|
end
|
128
97
|
|
129
|
-
|
130
|
-
|
131
|
-
@ordered_ids ||= begin
|
132
|
-
ActiveFedora::SolrService.query("proxy_in_ssi:#{id}",
|
133
|
-
rows: 10_000,
|
134
|
-
fl: "ordered_targets_ssim")
|
135
|
-
.flat_map { |x| x.fetch("ordered_targets_ssim", []) }
|
136
|
-
end
|
98
|
+
def member_presenter_factory
|
99
|
+
MemberPresenterFactory.new(solr_document, current_ability, request)
|
137
100
|
end
|
138
101
|
|
139
|
-
|
140
|
-
|
141
|
-
# Arbitrarily maxed at 10 thousand; had to specify rows due to solr's default of 10
|
142
|
-
def file_set_ids
|
143
|
-
@file_set_ids ||= begin
|
144
|
-
ActiveFedora::SolrService.query("{!field f=has_model_ssim}FileSet",
|
145
|
-
rows: 10_000,
|
146
|
-
fl: ActiveFedora.id_field,
|
147
|
-
fq: "{!join from=ordered_targets_ssim to=id}id:\"#{id}/list_source\"")
|
148
|
-
.flat_map { |x| x.fetch(ActiveFedora.id_field, []) }
|
149
|
-
end
|
102
|
+
def graph
|
103
|
+
GraphExporter.new(solr_document, request).fetch
|
150
104
|
end
|
151
105
|
end
|
152
106
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
<div class="form-group radio_buttons member_resource_options">
|
2
2
|
<span class="radio">
|
3
|
-
<%= radio_button_tag "thumbnail_id", node.id, @
|
3
|
+
<%= radio_button_tag "thumbnail_id", node.id, @form.thumbnail_id == node.id, id: "thumbnail_id_#{node.id}", class: "radio_buttons" %>
|
4
4
|
<%= label_tag "thumbnail_id_#{node.id}", "Thumbnail" %>
|
5
5
|
</span>
|
6
6
|
<span class="radio">
|
7
|
-
<%= radio_button_tag "representative_id", node.id, @
|
7
|
+
<%= radio_button_tag "representative_id", node.id, @form.representative_id == node.id, id: "representative_id_#{node.id}", class: "radio_buttons" %>
|
8
8
|
<%= label_tag "representative_id_#{node.id}", "Representative Media" %>
|
9
9
|
</span>
|
10
10
|
</div>
|
@@ -1,5 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
<%= content_tag :ul,
|
2
|
+
id: "sortable",
|
3
|
+
class: "list-unstyled grid clearfix",
|
4
|
+
data: {
|
5
|
+
id: @form.id,
|
6
|
+
"class-name" => @form.model_name.plural,
|
7
|
+
"singular-class-name" => @form.model_name.singular,
|
8
|
+
version: @form.version
|
9
|
+
} do %>
|
10
|
+
<% @form.member_presenters.each do |member| %>
|
11
|
+
<%= render "file_manager_member", node: member %>
|
12
|
+
<% end %>
|
13
|
+
<% end %>
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<div class="resource-form-container">
|
2
|
-
<%= simple_form_for [main_app, @
|
2
|
+
<%= simple_form_for [main_app, @form], remote: true, html: { id: 'resource-form', 'data-type': 'json' } do |f| %>
|
3
3
|
<%= f.input :thumbnail_id, as: :hidden, input_html: { data: {member_link: 'thumbnail_id'}} %>
|
4
4
|
<%= f.input :representative_id, as: :hidden, input_html: { data: {member_link: 'representative_id'}} %>
|
5
5
|
<% end %>
|
@@ -12,6 +12,9 @@
|
|
12
12
|
|
13
13
|
<div class="row">
|
14
14
|
<div class="col-md-12 form-actions">
|
15
|
+
<%# TODO: If we start using ActionCable, we could listen for object updates and
|
16
|
+
alert the user that the object has changed by someone else %>
|
17
|
+
<%= f.input CurationConcerns::OptimisticLockValidator.version_field, as: :hidden unless f.object.new_record? %>
|
15
18
|
<%= f.submit class: 'btn btn-primary require-contributor-agreement' %>
|
16
19
|
<% if curation_concern.new_record? %>
|
17
20
|
<%= link_to 'Cancel', main_app.root_path, class: 'btn btn-link' %>
|
@@ -1,11 +1,11 @@
|
|
1
1
|
<h1><%= t("file_manager.link_text") %></h1>
|
2
2
|
<ul class="breadcrumb">
|
3
3
|
<li>
|
4
|
-
Back to <%= link_to @
|
4
|
+
Back to <%= link_to @form.to_s, [main_app, @form] %>
|
5
5
|
</li>
|
6
6
|
</ul>
|
7
7
|
|
8
|
-
<% if !@
|
8
|
+
<% if !@form.member_presenters.empty? %>
|
9
9
|
<div data-action="file-manager">
|
10
10
|
<div class="col-md-3" id="file-manager-tools">
|
11
11
|
<h2>Toolbar</h2>
|
@@ -1 +1,2 @@
|
|
1
|
-
json.extract! @curation_concern, *[:id] + @curation_concern.class.fields.select {|f| ![:has_model].include? f}
|
1
|
+
json.extract! @curation_concern, *[:id] + @curation_concern.class.fields.select {|f| ![:has_model].include? f}
|
2
|
+
json.version @curation_concern.etag
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe CurationConcerns::OptimisticLockValidator do
|
4
|
+
let(:update_actor) do
|
5
|
+
double('update actor', update: true,
|
6
|
+
curation_concern: work,
|
7
|
+
user: depositor)
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:actor) do
|
11
|
+
CurationConcerns::Actors::ActorStack.new(work, depositor, [described_class])
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:depositor) { create(:user) }
|
15
|
+
let(:work) { create(:generic_work) }
|
16
|
+
|
17
|
+
describe "update" do
|
18
|
+
before do
|
19
|
+
allow(CurationConcerns::Actors::RootActor).to receive(:new).and_return(update_actor)
|
20
|
+
allow(update_actor).to receive(:update).and_return(true)
|
21
|
+
end
|
22
|
+
|
23
|
+
subject { actor.update(attributes) }
|
24
|
+
|
25
|
+
context "when version is blank" do
|
26
|
+
let(:attributes) { { version: '' } }
|
27
|
+
it { is_expected.to be true }
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when version is provided" do
|
31
|
+
context "and the version is current" do
|
32
|
+
let(:attributes) { { version: work.etag } }
|
33
|
+
|
34
|
+
it "returns true and calls the next actor without the version attribute" do
|
35
|
+
expect(update_actor).to receive(:update).with({}).and_return(true)
|
36
|
+
expect(subject).to be true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "and the version is not current" do
|
41
|
+
let(:attributes) { { version: "W/\"ab2e8552cb5f7f00f91d2b223eca45849c722301\"" } }
|
42
|
+
|
43
|
+
it "returns false and sets an error" do
|
44
|
+
expect(subject).to be false
|
45
|
+
expect(work.errors[:base]).to include "Another user has made a change to that Generic work since you accessed the edit form."
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -341,7 +341,7 @@ describe CurationConcerns::GenericWorksController do
|
|
341
341
|
it "is successful" do
|
342
342
|
get :file_manager, params: { id: work.id }
|
343
343
|
expect(response).to be_success
|
344
|
-
expect(assigns(:
|
344
|
+
expect(assigns(:form)).not_to be_blank
|
345
345
|
end
|
346
346
|
end
|
347
347
|
|
@@ -22,6 +22,14 @@ describe CurationConcerns::Forms::WorkForm do
|
|
22
22
|
let(:ability) { nil }
|
23
23
|
let(:form) { PirateShipForm.new(curation_concern, ability) }
|
24
24
|
|
25
|
+
describe "#version" do
|
26
|
+
before do
|
27
|
+
allow(curation_concern).to receive(:etag).and_return('123456')
|
28
|
+
end
|
29
|
+
subject { form.version }
|
30
|
+
it { is_expected.to eq '123456' }
|
31
|
+
end
|
32
|
+
|
25
33
|
describe "#select_files" do
|
26
34
|
let(:curation_concern) { create(:work_with_one_file) }
|
27
35
|
let(:title) { curation_concern.file_sets.first.title.first }
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe CurationConcerns::MemberPresenterFactory do
|
4
|
+
describe "#file_set_presenters" do
|
5
|
+
describe "getting presenters from factory" do
|
6
|
+
let(:solr_document) { SolrDocument.new(attributes) }
|
7
|
+
let(:attributes) { {} }
|
8
|
+
let(:ability) { double }
|
9
|
+
let(:request) { double }
|
10
|
+
let(:factory) { described_class.new(solr_document, ability, request) }
|
11
|
+
let(:presenter_class) { double }
|
12
|
+
before do
|
13
|
+
allow(factory).to receive(:composite_presenter_class).and_return(presenter_class)
|
14
|
+
allow(factory).to receive(:ordered_ids).and_return(['12', '33'])
|
15
|
+
allow(factory).to receive(:file_set_ids).and_return(['33', '12'])
|
16
|
+
end
|
17
|
+
|
18
|
+
it "uses the set class" do
|
19
|
+
expect(CurationConcerns::PresenterFactory).to receive(:build_presenters)
|
20
|
+
.with(['12', '33'], presenter_class, ability, request)
|
21
|
+
factory.file_set_presenters
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -102,34 +102,14 @@ describe CurationConcerns::WorkShowPresenter do
|
|
102
102
|
expect(presenter.file_set_presenters.map(&:id)).not_to include another_work.id
|
103
103
|
end
|
104
104
|
end
|
105
|
-
|
106
|
-
describe "getting presenters from factory" do
|
107
|
-
let(:attributes) { {} }
|
108
|
-
let(:presenter_class) { double }
|
109
|
-
before do
|
110
|
-
allow(presenter).to receive(:composite_presenter_class).and_return(presenter_class)
|
111
|
-
allow(presenter).to receive(:ordered_ids).and_return(['12', '33'])
|
112
|
-
allow(presenter).to receive(:file_set_ids).and_return(['33', '12'])
|
113
|
-
end
|
114
|
-
|
115
|
-
it "uses the set class" do
|
116
|
-
expect(CurationConcerns::PresenterFactory).to receive(:build_presenters)
|
117
|
-
.with(['12', '33'], presenter_class, ability, request)
|
118
|
-
presenter.file_set_presenters
|
119
|
-
end
|
120
|
-
end
|
121
105
|
end
|
122
106
|
|
123
107
|
describe "#representative_presenter" do
|
124
108
|
let(:obj) { create(:work_with_representative_file) }
|
125
109
|
let(:attributes) { obj.to_solr }
|
126
|
-
let(:presenter_class) { double }
|
127
|
-
before do
|
128
|
-
allow(presenter).to receive(:composite_presenter_class).and_return(presenter_class)
|
129
|
-
end
|
130
110
|
it "has a representative" do
|
131
111
|
expect(CurationConcerns::PresenterFactory).to receive(:build_presenters)
|
132
|
-
.with([obj.members[0].id],
|
112
|
+
.with([obj.members[0].id], CurationConcerns::CompositePresenterFactory, ability, request).and_return ["abc"]
|
133
113
|
expect(presenter.representative_presenter).to eq("abc")
|
134
114
|
end
|
135
115
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'curation_concerns/base/_form.html.erb', type: :view do
|
4
|
+
let(:ability) { double }
|
5
|
+
let(:user) { stub_model(User) }
|
6
|
+
let(:form) do
|
7
|
+
CurationConcerns::GenericWorkForm.new(work, ability)
|
8
|
+
end
|
9
|
+
|
10
|
+
before do
|
11
|
+
# view.lookup_context.view_paths.push 'app/views/curation_concerns'
|
12
|
+
# allow(controller).to receive(:current_user).and_return(user)
|
13
|
+
allow(view).to receive(:curation_concern).and_return(work)
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:page) do
|
17
|
+
view.simple_form_for form do |f|
|
18
|
+
render 'curation_concerns/base/form', f: f
|
19
|
+
end
|
20
|
+
Capybara::Node::Simple.new(rendered)
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when the work has been saved before" do
|
24
|
+
before do
|
25
|
+
allow(work).to receive(:new_record?).and_return(false)
|
26
|
+
assign(:form, form)
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:work) { stub_model(GenericWork, id: '456', etag: '123456') }
|
30
|
+
|
31
|
+
it "renders the form with the version" do
|
32
|
+
expect(page).to have_selector("input#generic_work_version[value=\"123456\"]", visible: false)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -26,19 +26,21 @@ RSpec.describe "curation_concerns/base/file_manager.html.erb" do
|
|
26
26
|
end
|
27
27
|
let(:resource) { FactoryGirl.build(:file_set) }
|
28
28
|
|
29
|
-
let(:parent) {
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
let(:parent_presenter) do
|
34
|
-
CurationConcerns::WorkShowPresenter.new(parent_solr_doc, nil, view)
|
29
|
+
let(:parent) { build(:generic_work) }
|
30
|
+
|
31
|
+
let(:form) do
|
32
|
+
CurationConcerns::Forms::FileManagerForm.new(parent, nil)
|
35
33
|
end
|
36
34
|
|
37
35
|
let(:blacklight_config) { CatalogController.new.blacklight_config }
|
38
36
|
|
39
37
|
before do
|
40
|
-
allow(
|
41
|
-
|
38
|
+
allow(parent).to receive(:etag).and_return("123456")
|
39
|
+
allow(parent).to receive(:persisted?).and_return(true)
|
40
|
+
allow(parent).to receive(:id).and_return('resource')
|
41
|
+
|
42
|
+
allow(form).to receive(:member_presenters).and_return([file_set, member])
|
43
|
+
assign(:form, form)
|
42
44
|
# Blacklight nonsense
|
43
45
|
allow(view).to receive(:dom_class) { '' }
|
44
46
|
allow(view).to receive(:blacklight_config).and_return(blacklight_config)
|
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe 'curation_concerns/base/show.json.jbuilder' do
|
4
|
-
let(:curation_concern) {
|
4
|
+
let(:curation_concern) { create(:generic_work) }
|
5
5
|
|
6
6
|
before do
|
7
|
+
allow(curation_concern).to receive(:etag).and_return('W/"87f79d2244ded4239ad1f0e822c8429b1e72b66c"')
|
7
8
|
assign(:curation_concern, curation_concern)
|
8
9
|
render
|
9
10
|
end
|
@@ -17,5 +18,6 @@ describe 'curation_concerns/base/show.json.jbuilder' do
|
|
17
18
|
expected_fields.each do |field_symbol|
|
18
19
|
expect(json).to have_key(field_symbol.to_s)
|
19
20
|
end
|
21
|
+
expect(json['version']).to eq 'W/"87f79d2244ded4239ad1f0e822c8429b1e72b66c"'
|
20
22
|
end
|
21
23
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: curation_concerns
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.7.
|
4
|
+
version: 1.7.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Zumwalt
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2017-02-
|
13
|
+
date: 2017-02-07 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: hydra-head
|
@@ -771,6 +771,7 @@ files:
|
|
771
771
|
- app/actors/curation_concerns/actors/interpret_visibility_actor.rb
|
772
772
|
- app/actors/curation_concerns/actors/lease_actor.rb
|
773
773
|
- app/actors/curation_concerns/actors/root_actor.rb
|
774
|
+
- app/actors/curation_concerns/optimistic_lock_validator.rb
|
774
775
|
- app/assets/images/audio.png
|
775
776
|
- app/assets/images/default.png
|
776
777
|
- app/assets/images/loading.gif
|
@@ -863,6 +864,7 @@ files:
|
|
863
864
|
- app/conversions/power_converters/sipity_workflow_state.rb
|
864
865
|
- app/forms/curation_concerns/forms.rb
|
865
866
|
- app/forms/curation_concerns/forms/collection_edit_form.rb
|
867
|
+
- app/forms/curation_concerns/forms/file_manager_form.rb
|
866
868
|
- app/forms/curation_concerns/forms/file_set_edit_form.rb
|
867
869
|
- app/forms/curation_concerns/forms/work_form.rb
|
868
870
|
- app/forms/curation_concerns/forms/workflow_action_form.rb
|
@@ -958,6 +960,7 @@ files:
|
|
958
960
|
- app/presenters/curation_concerns/file_set_presenter.rb
|
959
961
|
- app/presenters/curation_concerns/inspect_work_presenter.rb
|
960
962
|
- app/presenters/curation_concerns/lease_presenter.rb
|
963
|
+
- app/presenters/curation_concerns/member_presenter_factory.rb
|
961
964
|
- app/presenters/curation_concerns/model_proxy.rb
|
962
965
|
- app/presenters/curation_concerns/permission_badge.rb
|
963
966
|
- app/presenters/curation_concerns/presenter_factory.rb
|
@@ -1318,6 +1321,7 @@ files:
|
|
1318
1321
|
- spec/actors/curation_concerns/initialize_workflow_actor_spec.rb
|
1319
1322
|
- spec/actors/curation_concerns/interpret_visibility_actor_spec.rb
|
1320
1323
|
- spec/actors/curation_concerns/lease_actor_spec.rb
|
1324
|
+
- spec/actors/curation_concerns/optimistic_lock_validator_spec.rb
|
1321
1325
|
- spec/actors/curation_concerns/work_actor_spec.rb
|
1322
1326
|
- spec/controllers/accepts_batches_controller_spec.rb
|
1323
1327
|
- spec/controllers/catalog_controller_spec.rb
|
@@ -1457,6 +1461,7 @@ files:
|
|
1457
1461
|
- spec/presenters/curation_concerns/collection_presenter_spec.rb
|
1458
1462
|
- spec/presenters/curation_concerns/file_set_presenter_spec.rb
|
1459
1463
|
- spec/presenters/curation_concerns/inspect_work_presenter_spec.rb
|
1464
|
+
- spec/presenters/curation_concerns/member_presenter_factory_spec.rb
|
1460
1465
|
- spec/presenters/curation_concerns/permission_badge_spec.rb
|
1461
1466
|
- spec/presenters/curation_concerns/presenter_factory_spec.rb
|
1462
1467
|
- spec/presenters/curation_concerns/single_use_link_presenter_spec.rb
|
@@ -1544,6 +1549,7 @@ files:
|
|
1544
1549
|
- spec/views/curation_concerns/admin/index.html.erb_spec.rb
|
1545
1550
|
- spec/views/curation_concerns/admin/widgets/_pie.html.erb_spec.rb
|
1546
1551
|
- spec/views/curation_concerns/base/_attributes.html.erb_spec.rb
|
1552
|
+
- spec/views/curation_concerns/base/_form.html.erb_spec.rb
|
1547
1553
|
- spec/views/curation_concerns/base/_form_rights_spec.rb
|
1548
1554
|
- spec/views/curation_concerns/base/_member.html.erb_spec.rb
|
1549
1555
|
- spec/views/curation_concerns/base/_show_actions.html.erb_spec.rb
|
@@ -1591,7 +1597,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1591
1597
|
version: '0'
|
1592
1598
|
requirements: []
|
1593
1599
|
rubyforge_project:
|
1594
|
-
rubygems_version: 2.
|
1600
|
+
rubygems_version: 2.6.8
|
1595
1601
|
signing_key:
|
1596
1602
|
specification_version: 4
|
1597
1603
|
summary: A Rails Engine that allows an application to CRUD CurationConcern objects
|
@@ -1612,6 +1618,7 @@ test_files:
|
|
1612
1618
|
- spec/actors/curation_concerns/initialize_workflow_actor_spec.rb
|
1613
1619
|
- spec/actors/curation_concerns/interpret_visibility_actor_spec.rb
|
1614
1620
|
- spec/actors/curation_concerns/lease_actor_spec.rb
|
1621
|
+
- spec/actors/curation_concerns/optimistic_lock_validator_spec.rb
|
1615
1622
|
- spec/actors/curation_concerns/work_actor_spec.rb
|
1616
1623
|
- spec/controllers/accepts_batches_controller_spec.rb
|
1617
1624
|
- spec/controllers/catalog_controller_spec.rb
|
@@ -1751,6 +1758,7 @@ test_files:
|
|
1751
1758
|
- spec/presenters/curation_concerns/collection_presenter_spec.rb
|
1752
1759
|
- spec/presenters/curation_concerns/file_set_presenter_spec.rb
|
1753
1760
|
- spec/presenters/curation_concerns/inspect_work_presenter_spec.rb
|
1761
|
+
- spec/presenters/curation_concerns/member_presenter_factory_spec.rb
|
1754
1762
|
- spec/presenters/curation_concerns/permission_badge_spec.rb
|
1755
1763
|
- spec/presenters/curation_concerns/presenter_factory_spec.rb
|
1756
1764
|
- spec/presenters/curation_concerns/single_use_link_presenter_spec.rb
|
@@ -1838,6 +1846,7 @@ test_files:
|
|
1838
1846
|
- spec/views/curation_concerns/admin/index.html.erb_spec.rb
|
1839
1847
|
- spec/views/curation_concerns/admin/widgets/_pie.html.erb_spec.rb
|
1840
1848
|
- spec/views/curation_concerns/base/_attributes.html.erb_spec.rb
|
1849
|
+
- spec/views/curation_concerns/base/_form.html.erb_spec.rb
|
1841
1850
|
- spec/views/curation_concerns/base/_form_rights_spec.rb
|
1842
1851
|
- spec/views/curation_concerns/base/_member.html.erb_spec.rb
|
1843
1852
|
- spec/views/curation_concerns/base/_show_actions.html.erb_spec.rb
|