module Hyrax module Actors class InterpretVisibilityActor < AbstractActor class Intention def initialize(attributes) @attributes = attributes end # returns a copy of attributes with the necessary params removed # If the lease or embargo is valid, or if they selected something besides lease # or embargo, remove all the params. def sanitize_params if valid_lease? sanitize_lease_params elsif valid_embargo? sanitize_embargo_params elsif !wants_lease? && !wants_embargo? sanitize_unrestricted_params else @attributes end end def wants_lease? visibility == Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_LEASE end def wants_embargo? visibility == Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_EMBARGO end def valid_lease? wants_lease? && @attributes[:lease_expiration_date].present? end def valid_embargo? wants_embargo? && @attributes[:embargo_release_date].present? end def lease_params [:lease_expiration_date, :visibility_during_lease, :visibility_after_lease].map { |key| @attributes[key] } end def embargo_params [:embargo_release_date, :visibility_during_embargo, :visibility_after_embargo].map { |key| @attributes[key] } end private def sanitize_unrestricted_params @attributes.except(:lease_expiration_date, :visibility_during_lease, :visibility_after_lease, :embargo_release_date, :visibility_during_embargo, :visibility_after_embargo) end def sanitize_embargo_params @attributes.except(:visibility, :lease_expiration_date, :visibility_during_lease, :visibility_after_lease) end def sanitize_lease_params @attributes.except(:visibility, :embargo_release_date, :visibility_during_embargo, :visibility_after_embargo) end def visibility @attributes[:visibility] end end # @param [Hyrax::Actors::Environment] env # @return [Boolean] true if create was successful def create(env) intention = Intention.new(env.attributes) attributes = intention.sanitize_params new_env = Environment.new(env.curation_concern, env.current_ability, attributes) validate(env, intention, attributes) && apply_visibility(new_env, intention) && next_actor.create(new_env) end # @param [Hyrax::Actors::Environment] env # @return [Boolean] true if update was successful def update(env) intention = Intention.new(env.attributes) attributes = intention.sanitize_params new_env = Environment.new(env.curation_concern, env.current_ability, attributes) validate(env, intention, attributes) && apply_visibility(new_env, intention) && next_actor.update(new_env) end private # Validate against selected AdminSet's PermissionTemplate (if any) def validate(env, intention, attributes) # If AdminSet was selected, look for its PermissionTemplate template = PermissionTemplate.find_by!(source_id: attributes[:admin_set_id]) if attributes[:admin_set_id].present? validate_lease(env, intention, template) && validate_release_type(env, intention, template) && validate_visibility(env, attributes, template) && validate_embargo(env, intention, attributes, template) end def apply_visibility(env, intention) result = apply_lease(env, intention) && apply_embargo(env, intention) env.curation_concern.visibility = env.attributes[:visibility] if env.attributes[:visibility] result end # Validate that a lease is allowed by AdminSet's PermissionTemplate def validate_lease(env, intention, template) return true unless intention.wants_lease? # Leases are only allowable if a template doesn't require a release period or have any specific visibility requirement # (Note: permission template release/visibility options do not support leases) unless template.present? && (template.release_period.present? || template.visibility.present?) return true if intention.valid_lease? env.curation_concern.errors.add(:visibility, 'When setting visibility to "lease" you must also specify lease expiration date.') return false end env.curation_concern.errors.add(:visibility, 'Lease option is not allowed by permission template for selected AdminSet.') false end # Validate the selected release settings against template, checking for when embargoes/leases are not allowed def validate_release_type(env, intention, template) # It's valid as long as embargo is not specified when a template requires no release delays return true unless intention.wants_embargo? && template.present? && template.release_no_delay? env.curation_concern.errors.add(:visibility, 'Visibility specified does not match permission template "no release delay" requirement for selected AdminSet.') false end # Validate visibility complies with AdminSet template requirements def validate_visibility(env, attributes, template) # NOTE: For embargo/lease, attributes[:visibility] will be nil (see sanitize_params), so visibility will be validated as part of embargo/lease return true if attributes[:visibility].blank? # Validate against template's visibility requirements return true if validate_template_visibility(attributes[:visibility], template) env.curation_concern.errors.add(:visibility, 'Visibility specified does not match permission template visibility requirement for selected AdminSet.') false end # When specified, validate embargo is a future date that complies with AdminSet template requirements (if any) def validate_embargo(env, intention, attributes, template) return true unless intention.wants_embargo? embargo_release_date = parse_date(attributes[:embargo_release_date]) # When embargo required, date must be in future AND matches any template requirements return true if valid_future_date?(env, embargo_release_date) && valid_template_embargo_date?(env, embargo_release_date, template) && valid_template_visibility_after_embargo?(env, attributes, template) env.curation_concern.errors.add(:visibility, 'When setting visibility to "embargo" you must also specify embargo release date.') if embargo_release_date.blank? false end # Validate an date attribute is in the future def valid_future_date?(env, date, attribute_name: :embargo_release_date) return true if date.present? && date.future? env.curation_concern.errors.add(attribute_name, "Must be a future date.") false end # Validate an embargo date against permission template restrictions def valid_template_embargo_date?(env, date, template) return true if template.blank? # Validate against template's release_date requirements return true if template.valid_release_date?(date) env.curation_concern.errors.add(:embargo_release_date, "Release date specified does not match permission template release requirements for selected AdminSet.") false end # Validate the post-embargo visibility against permission template requirements (if any) def valid_template_visibility_after_embargo?(env, attributes, template) # Validate against template's visibility requirements return true if validate_template_visibility(attributes[:visibility_after_embargo], template) env.curation_concern.errors.add(:visibility_after_embargo, "Visibility after embargo does not match permission template visibility requirements for selected AdminSet.") false end # Validate that a given visibility value satisfies template requirements def validate_template_visibility(visibility, template) return true if template.blank? template.valid_visibility?(visibility) end # Parse date from string. Returns nil if date_string is not a valid date def parse_date(date_string) datetime = Time.zone.parse(date_string) if date_string.present? return datetime.to_date unless datetime.nil? nil end # If they want a lease, we can assume it's valid def apply_lease(env, intention) return true unless intention.wants_lease? env.curation_concern.apply_lease(*intention.lease_params) return unless env.curation_concern.lease env.curation_concern.lease.save # see https://github.com/samvera/hydra-head/issues/226 end # If they want an embargo, we can assume it's valid def apply_embargo(env, intention) return true unless intention.wants_embargo? env.curation_concern.apply_embargo(*intention.embargo_params) return unless env.curation_concern.embargo env.curation_concern.embargo.save # see https://github.com/samvera/hydra-head/issues/226 end end end end