Skip to content

Commit

Permalink
Merge pull request seek4science#1907 from seek4science/github-app-sup…
Browse files Browse the repository at this point in the history
…port

RO-Crate submission API
  • Loading branch information
fbacall authored Jun 28, 2024
2 parents 56d7375 + fc037d8 commit a29c221
Show file tree
Hide file tree
Showing 15 changed files with 281 additions and 32 deletions.
3 changes: 2 additions & 1 deletion app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,8 @@ def json_api_errors(object)
hash[:errors] = object.errors.map do |error|
segments = error.attribute.to_s.split('.')
attr = segments.first
if !['content_blobs', 'policy'].include?(attr) && object.class.reflect_on_association(attr)
if !['content_blobs', 'policy'].include?(attr) &&
object.class.respond_to?(:reflect_on_association) && object.class.reflect_on_association(attr)
base = '/data/relationships'
else
base = '/data/attributes'
Expand Down
20 changes: 18 additions & 2 deletions app/controllers/workflows_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ class WorkflowsController < ApplicationController
before_action :find_display_asset, only: [:show, :download, :diagram, :ro_crate, :ro_crate_metadata, :edit_paths, :update_paths]
before_action :login_required, only: [:create, :create_version, :new_version,
:create_from_files, :create_from_ro_crate,
:create_metadata, :provide_metadata, :create_from_git, :create_version_from_git]
:create_metadata, :provide_metadata, :create_from_git, :create_version_from_git,
:submit]
before_action :find_or_initialize_workflow, only: [:create_from_files, :create_from_ro_crate]

include Seek::Publishing::PublishingCommon
Expand Down Expand Up @@ -307,6 +308,21 @@ def filter
end
end

def submit
@crate_extractor = WorkflowCrateExtractor.new(ro_crate: { data: params[:ro_crate] }, params: workflow_params, update_existing: true)

if @crate_extractor.valid?
@workflow = @crate_extractor.build
if @workflow.git_version.save && @workflow.save
render json: @workflow, include: json_api_include_param
else
render json: json_api_errors(@workflow), status: :unprocessable_entity
end
else
render json: json_api_errors(@crate_extractor), status: :unprocessable_entity
end
end

private

def handle_ro_crate_post(new_version = false)
Expand All @@ -321,7 +337,7 @@ def handle_ro_crate_post(new_version = false)
else
@crate_extractor.workflow = @workflow
@workflow.latest_git_version.lock if @workflow.latest_git_version.mutable?
@crate_extractor.git_version = @workflow.latest_git_version.next_version(mutable: true).tap(&:save)
@crate_extractor.git_version = @workflow.latest_git_version.next_version(mutable: true)
end
end
@workflow = @crate_extractor.build
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,29 @@
class WorkflowCrateExtractor
include ActiveModel::Model

attr_accessor :ro_crate, :workflow_class, :workflow, :git_version, :params
attr_accessor :ro_crate, :workflow_class, :workflow, :git_version, :params, :update_existing

validate :resolve_crate
validate :main_workflow_present?, if: -> { @crate.present? }
validate :source_url_and_version_present?, if: -> { update_existing }
validate :find_workflows_matching_id, if: -> { update_existing }

def build
self.workflow ||= Workflow.new(workflow_class: workflow_class)
if valid?
if update_existing && @existing_workflows.length == 1
self.workflow = @existing_workflows.first
if self.workflow.git_versions.map(&:name).include?(@crate['version']&.to_s)
return self.workflow
else
self.workflow.latest_git_version.lock if self.workflow.latest_git_version.mutable?
self.git_version = self.workflow.latest_git_version.next_version(mutable: true)
end
end
self.workflow ||= default_workflow
self.git_version ||= workflow.git_version.tap do |gv|
gv.set_default_git_repository
end
self.git_version.name = @crate['version'].to_s if @crate['version']
git_version.main_workflow_path = URI.decode_www_form_component(@crate.main_workflow.id) if @crate.main_workflow && !@crate.main_workflow.remote?
git_version.diagram_path = URI.decode_www_form_component(@crate.main_workflow.diagram.id) if @crate.main_workflow&.diagram && !@crate.main_workflow.diagram.remote?
git_version.abstract_cwl_path = URI.decode_www_form_component(@crate.main_workflow.cwl_description.id) if @crate.main_workflow&.cwl_description && !@crate.main_workflow.cwl_description.remote?
Expand All @@ -30,19 +42,34 @@ def build
workflow.provide_metadata(extractor.metadata)
workflow.assign_attributes(params) if params.present?
git_version.set_resource_attributes(workflow.attributes)

workflow
end

workflow
workflow || default_workflow
end

private

def default_workflow
Workflow.new(workflow_class: workflow_class)
end

def main_workflow_present?
errors.add(:ro_crate, 'did not specify a main workflow.') unless @crate.main_workflow.present?
end

def source_url_and_version_present?
errors.add(:ro_crate, 'source URL could not be determined.') unless @crate.source_url.present?
errors.add(:ro_crate, 'version could not be determined.') unless @crate['version'].present?
end

def find_workflows_matching_id
# Attempt to find existing workflow
@existing_workflows = Workflow.find_by_source_url(@crate.source_url)
if @existing_workflows.length > 1
errors.add(:ro_crate, "#{@existing_workflows.length} workflows found matching the given ID.")
end
end

def extract_crate
begin
@crate = ROCrate::WorkflowCrateReader.read_zip(ro_crate[:data])
Expand Down
File renamed without changes.
4 changes: 3 additions & 1 deletion app/models/concerns/workflow_extraction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,9 @@ def ro_crate_url(action = nil)
end

if exist
exist.update_attribute(:path, path)
exist.path = path
exist.save(validate: false) if exist.persisted?
exist
else
git_version.git_annotations.build(key: s_type, path: path)
end
Expand Down
1 change: 1 addition & 0 deletions app/models/git/annotation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class Annotation < ApplicationRecord
before_validation :assign_contributor

validates :key, uniqueness: { scope: [:git_version_id, :path, :value] }
validates :git_version, presence: true
validate :check_valid_path

def assign_contributor
Expand Down
3 changes: 3 additions & 0 deletions app/models/workflow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -274,4 +274,7 @@ def execution_instance_url
}
)

def self.find_by_source_url(source_url)
joins(:source_link).where('asset_links.url' => source_url)
end
end
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,7 @@
post :create_from_ro_crate
post :create_from_files
post :create_from_git
post :submit
get :provide_metadata
get :annotate_repository
post :create_metadata
Expand Down
5 changes: 5 additions & 0 deletions lib/ro_crate/workflow_crate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,10 @@ def test_suites
def find_entry(path)
entries[path]
end

def source_url
url = id if id.start_with?('http')
url || self['isBasedOn'] || self['url'] || self.main_workflow['url']
end
end
end
10 changes: 5 additions & 5 deletions lib/seek/workflow_extractors/ro_crate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,11 @@ def metadata_from_crate(crate, m)
end
end

source_url = crate['isBasedOn'] || crate['url'] || crate.main_workflow['url']
if source_url
m.merge!(extract_source_metadata(ContentBlob.remote_content_handler_for(source_url)))
m[:source_link_url] ||= source_url # Use plain source URL if handler doesn't have something more appropriate
end
source_url = crate.source_url
if source_url
m.merge!(extract_source_metadata(ContentBlob.remote_content_handler_for(source_url)))
m[:source_link_url] ||= source_url # Use plain source URL if handler doesn't have something more appropriate
end

m
end
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit a29c221

Please sign in to comment.