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
         |