curation_concerns 1.7.3 → 1.7.4
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/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
|