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.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/app/actors/curation_concerns/optimistic_lock_validator.rb +28 -0
  3. data/app/assets/javascripts/curation_concerns/file_manager/sorting.es6 +17 -7
  4. data/app/controllers/concerns/curation_concerns/curation_concern_controller.rb +6 -1
  5. data/app/forms/curation_concerns/forms/file_manager_form.rb +27 -0
  6. data/app/forms/curation_concerns/forms/work_form.rb +8 -0
  7. data/app/models/concerns/curation_concerns/ability.rb +1 -0
  8. data/app/models/concerns/curation_concerns/work_behavior.rb +6 -0
  9. data/app/presenters/curation_concerns/member_presenter_factory.rb +70 -0
  10. data/app/presenters/curation_concerns/work_show_presenter.rb +7 -53
  11. data/app/services/curation_concerns/actors/actor_factory.rb +2 -1
  12. data/app/views/curation_concerns/base/_file_manager_member_resource_options.html.erb +2 -2
  13. data/app/views/curation_concerns/base/_file_manager_members.html.erb +13 -5
  14. data/app/views/curation_concerns/base/_file_manager_resource_form.html.erb +1 -1
  15. data/app/views/curation_concerns/base/_form.html.erb +3 -0
  16. data/app/views/curation_concerns/base/file_manager.html.erb +2 -2
  17. data/app/views/curation_concerns/base/show.json.jbuilder +2 -1
  18. data/config/locales/curation_concerns.en.yml +4 -0
  19. data/lib/curation_concerns/version.rb +1 -1
  20. data/spec/actors/curation_concerns/optimistic_lock_validator_spec.rb +50 -0
  21. data/spec/controllers/curation_concerns/generic_works_controller_spec.rb +1 -1
  22. data/spec/forms/work_form_spec.rb +8 -0
  23. data/spec/presenters/curation_concerns/member_presenter_factory_spec.rb +25 -0
  24. data/spec/presenters/curation_concerns/work_show_presenter_spec.rb +1 -21
  25. data/spec/views/curation_concerns/base/_form.html.erb_spec.rb +35 -0
  26. data/spec/views/curation_concerns/base/file_manager.html.erb_spec.rb +10 -8
  27. data/spec/views/curation_concerns/base/show.json.jbuilder_spec.rb +3 -1
  28. metadata +12 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b8e3a51d73c77e6ee4533319b2e0dbc7b8afed1c
4
- data.tar.gz: c1cb7a95bc11873894ec02b198c0925db1e1ff27
3
+ metadata.gz: 0264d3ffe1409c035fd9849f11c7ade0dc92c3c1
4
+ data.tar.gz: 912f6765b87b3ebe922ccc17ea4689925fe03acb
5
5
  SHA512:
6
- metadata.gz: 7617b194446b007e5b23f6f58d9f5ba08f57f6bf26a46b07264141688c751aec136adf36a409f52d73b87280c24e012652cbb94798ff613938edffb1b420c33d
7
- data.tar.gz: e542b1d43ab5205cd042a4fa6c7398a7bcbfd2956c7fbd92a092d3ef3fcec932b40503bc6e9122125080e2ecd34595ccf1d85e5117a37f9f9388edd9a295e50f
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
- presenter
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
@@ -14,6 +14,7 @@ module CurationConcerns
14
14
 
15
15
  # user can version if they can edit
16
16
  alias_action :versions, to: :update
17
+ alias_action :file_manager, to: :update
17
18
 
18
19
  if admin?
19
20
  admin_permissions
@@ -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, :file_presenter_class, :work_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
- private
83
+ delegate :member_presenters, :file_set_presenters, :work_presenters, to: :member_presenter_factory
113
84
 
114
- def graph
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
- # TODO: Extract this to ActiveFedora::Aggregations::ListSource
130
- def ordered_ids
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
- # These are the file sets that belong to this work, but not necessarily
140
- # in order.
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
@@ -8,7 +8,8 @@ module CurationConcerns
8
8
  end
9
9
 
10
10
  def self.stack_actors(curation_concern)
11
- [AddToCollectionActor,
11
+ [OptimisticLockValidator,
12
+ AddToCollectionActor,
12
13
  AddToWorkActor,
13
14
  AssignRepresentativeActor,
14
15
  AttachFilesActor,
@@ -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, @presenter.thumbnail_id == node.id, id: "thumbnail_id_#{node.id}", class: "radio_buttons" %>
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, @presenter.representative_id == node.id, id: "representative_id_#{node.id}", class: "radio_buttons" %>
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
- <ul id="sortable" data-id="<%= @presenter.id %>" data-class-name="<%= @presenter.model_name.plural %>" data-singular-class-name="<%= @presenter.model_name.singular %>" class="list-unstyled grid clearfix">
2
- <% @presenter.member_presenters.each do |member| %>
3
- <%= render "file_manager_member", node: member %>
4
- <% end %>
5
- </ul>
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, @presenter], remote: true, html: { id: 'resource-form', 'data-type': 'json' } do |f| %>
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 @presenter.to_s, [main_app, @presenter] %>
4
+ Back to <%= link_to @form.to_s, [main_app, @form] %>
5
5
  </li>
6
6
  </ul>
7
7
 
8
- <% if !@presenter.member_presenters.empty? %>
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
@@ -1,4 +1,8 @@
1
1
  en:
2
+ activemodel:
3
+ errors:
4
+ messages:
5
+ conflict: "Another user has made a change to that %{model} since you accessed the edit form."
2
6
  curation_concerns:
3
7
  admin:
4
8
  workflow_roles:
@@ -1,3 +1,3 @@
1
1
  module CurationConcerns
2
- VERSION = '1.7.3'.freeze
2
+ VERSION = '1.7.4'.freeze
3
3
  end
@@ -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(:presenter)).not_to be_blank
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], presenter_class, ability, request).and_return ["abc"]
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) { FactoryGirl.build(:generic_work) }
30
- let(:parent_solr_doc) do
31
- SolrDocument.new(parent.to_solr.merge(id: "resource"), nil)
32
- end
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(parent_presenter).to receive(:member_presenters).and_return([file_set, member])
41
- assign(:presenter, parent_presenter)
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) { FactoryGirl.create(:generic_work) }
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.3
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-03 00:00:00.000000000 Z
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.5.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