Skip to content

Commit

Permalink
Adding the ability to call to mediaflux to push an update for the sub…
Browse files Browse the repository at this point in the history
…mission event (#738)

Unfortunately we have to replace the entire document we can not just replace single elements.
  • Loading branch information
carolyncole authored Jun 3, 2024
1 parent c79a8e3 commit e18fd9f
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 4 deletions.
170 changes: 170 additions & 0 deletions app/models/mediaflux/http/asset_approve_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# frozen_string_literal: true
module Mediaflux
module Http
# Constructs a request to mediaflux to approve a project
#
# @example
# project = Project.first
# project.save_in_mediaflux(session_id: User.first.mediaflux_session)
# approve_req = Mediaflux::Http::AssetApproveRequest.new(session_token: User.first.mediaflux_session, project:)
# approve_req.resolve
#
class AssetApproveRequest < Request
attr_reader :project_metadata, :project
# Constructor
# @param session_token [String] the API token for the authenticated session
# @param project [Project] project to approve
# @param xml_namespace [String] XML namespace for the <project> element
def initialize(session_token:, project:, xml_namespace: nil, xml_namespace_uri: nil)
super(session_token: session_token)
@project = project
@project_metadata = project.metadata
@xml_namespace = xml_namespace || self.class.default_xml_namespace
@xml_namespace_uri = xml_namespace_uri || self.class.default_xml_namespace_uri
end

# Specifies the Mediaflux service to use when updating assets
# @return [String]
def self.service
"asset.set"
end

private

# The generated XML mimics what we get when we issue an Aterm command as follows:
# service.execute :service -name "asset.set" \
# < :id "1574" :meta -action "replace" < :tigerdata:project -xmlns:tigerdata "tigerdata" < \
# :ProjectDirectory "/td-demo-001/tigerdataNS/test-05-30-24" :Title "testing approval" :Description "I want to test the approval updates" \
# :Status "approved" :DataSponsor "cac9" :DataManager "mjc12" :Department "RDSS" :DataUser -ReadOnly "true" "la15" :DataUser "woongkim" \
# :CreatedOn "30-MAY-2024 09:11:09" :CreatedBy "cac9" :ProjectID "10.34770/tbd"
# :StorageCapacity < :Size -Requested "500" -Approved "1" "1" :Unit -Requested "GB" -Approved "TB" "TB" > \
# :Performance -Requested "Standard" -Approved "Standard" "Standard" :Submission < :RequestedBy "cac9" \
# :RequestDateTime "30-MAY-2024 13:11:09" :ApprovedBy "cac9" :ApprovalDateTime "30-MAY-2024 13:12:44" \
# :EventlNote < :NoteDateTime "30-MAY-2024 13:12:44" :NoteBy "cac9" :EventType "Quota" :Message "A note"\
# > > :ProjectPurpose "Research" :SchemaVersion "0.6.1" > > >
#
def build_http_request_body(name:)
super do |xml|
xml.args do
xml.id project.mediaflux_id
xml.meta do
xml.parent.set_attribute("action", "replace")
doc = xml.doc
root = doc.root
# Define the namespace only if this is required
root.add_namespace_definition(@xml_namespace, @xml_namespace_uri)

element_name = @xml_namespace.nil? ? "project" : "#{@xml_namespace}:project"
xml.send(element_name) do
build_project(xml)
end
end
end
end
end

def build_project(xml)
build_basic_project_meta(xml)
build_departments(xml, project_metadata[:departments])
build_read_only_user(xml, project_metadata[:data_user_read_only])
build_read_write_users(xml, project_metadata[:data_user_read_write])
xml.CreatedOn self.class.format_date_for_mediaflux(project_metadata[:created_on])
xml.CreatedBy project_metadata[:created_by]
xml.ProjectID project_metadata[:project_id]
build_storage_capacity(xml)
build_performance(xml)
build_submission(xml)
xml.ProjectPurpose project_metadata[:project_purpose]
xml.SchemaVersion TigerdataSchema::SCHEMA_VERSION
end

def build_basic_project_meta(xml)
xml.ProjectDirectory project_metadata[:project_directory]
xml.Title project_metadata[:title]
xml.Description project_metadata[:description] if project_metadata[:description].present?
xml.Status project_metadata[:status]
xml.DataSponsor project_metadata[:data_sponsor]
xml.DataManager project_metadata[:data_manager]
end

def build_departments(xml, departments)
return if departments.blank?

departments.each do |department|
xml.Department department
end
end

def build_read_only_user(xml, ro_users)
return if ro_users.blank?

ro_users.each do |ro_user|
xml.DataUser do
xml.parent.set_attribute("ReadOnly", true)
xml.text(ro_user)
end
end
end

def build_read_write_users(xml, rw_users)
return if rw_users.blank?

rw_users.each do |rw_user|
xml.DataUser rw_user
end
end

def build_storage_capacity(xml)
xml.StorageCapacity do
xml.Size do
build_value(xml, project_metadata[:storage_capacity][:size][:requested], project_metadata[:storage_capacity][:size][:approved])
end
xml.Unit do
build_value(xml, project_metadata[:storage_capacity][:unit][:requested], project_metadata[:storage_capacity][:unit][:approved])
end
end
end

def build_performance(xml)
xml.Performance do
build_value(xml, project_metadata[:storage_performance_expectations][:requested], project_metadata[:storage_performance_expectations][:approved])
end
end

def build_value(xml, requested, approved)
xml.parent.set_attribute("Requested", requested)
xml.parent.set_attribute("Approved", approved)
xml.text(approved)
end

def build_submission(xml)
xml.Submission do
xml.RequestedBy submission_event.event_person
xml.RequestDateTime self.class.format_date_for_mediaflux(submission_event.created_at.iso8601)
xml.ApprovedBy approval_event.event_person
xml.ApprovalDateTime self.class.format_date_for_mediaflux(approval_event.created_at.iso8601)
build_submission_note(xml)
end
end

def build_submission_note(xml)
return if approval_event.event_note.blank?

xml.EventlNote do
xml.NoteDateTime self.class.format_date_for_mediaflux(approval_event.created_at.iso8601)
xml.NoteBy approval_event.event_note["note_by"]
xml.EventType approval_event.event_note["event_type"]
xml.Message approval_event.event_note["message"]
end
end

def approval_event
@approval_event ||= project.provenance_events.find_by(event_type: ProvenanceEvent::APPROVAL_EVENT_TYPE)
end

def submission_event
@submission_event ||= project.provenance_events.find_by(event_type: ProvenanceEvent::SUBMISSION_EVENT_TYPE)
end
end
end
end
7 changes: 7 additions & 0 deletions app/models/mediaflux/http/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ def xtoshell_xml( name: self.class.service)
xml.strip.gsub("\"","'").gsub("<args>","").gsub("</args>","")
end

# This method is used for transforming iso8601 dates to dates that MediaFlux likes
# Take a string like "2024-02-26T10:33:11-05:00" and convert this string to "22-FEB-2024 13:57:19"
def self.format_date_for_mediaflux(iso8601_date)
return if iso8601_date.nil?
Time.parse(iso8601_date).strftime("%e-%b-%Y %H:%M:%S").upcase
end

private

def http_request
Expand Down
7 changes: 6 additions & 1 deletion app/models/project_metadata.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,16 @@ def approve_project(params:)
project.metadata_json["status"] = Project::APPROVED_STATUS
project.metadata_json["project_directory"] = "#{params[:project_directory_prefix]}/#{params[:project_directory]}"
project.metadata_json["storage_capacity"] = params[:storage_capacity]
project.metadata_json["storage_performance_expectations"] = params[:storage_performance_expectations]

project.save!
generate_approval_events(params[:approval_note])
end

def generate_approval_events(note)
# create two provenance events, one for approving the project and another for changing the status of the project
project.provenance_events.create(event_type: ProvenanceEvent::APPROVAL_EVENT_TYPE, event_person: current_user.uid, event_details: "Approved by #{current_user.display_name_safe}",
event_note: params[:approval_note])
event_note: note)
project.provenance_events.create(event_type: ProvenanceEvent::STATUS_UPDATE_EVENT_TYPE, event_person: current_user.uid, event_details: "The Status of this project has been set to approved")
end

Expand Down
17 changes: 16 additions & 1 deletion spec/factories/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
project_purpose { "research" }
project_directory { "big-data" }
schema_version { ::TigerdataSchema::SCHEMA_VERSION }
approved_by { nil }
approved_on { nil }
end
mediaflux_id { nil }
metadata do
Expand All @@ -38,7 +40,9 @@
storage_capacity: storage_capacity,
storage_performance_expectations: storage_performance,
project_purpose: project_purpose,
schema_version: schema_version
schema_version: schema_version,
approved_by: approved_by,
approved_on: approved_on
}
end
factory :project_with_doi, class: "Project" do
Expand All @@ -53,5 +57,16 @@
end
end
end

factory :approved_project, class: "Project" do
transient do
storage_capacity { { size: { requested: 500, approved: 600 }, unit: { requested: "GB", approved: "KB" } } }
storage_performance { { requested: "standard", approved: "performant" } }
status { "approved" }
approved_by { FactoryBot.create(:sysadmin).uid }
approved_on { Time.current.in_time_zone("America/New_York").iso8601 }
project_id { "10.34770/tbd" }
end
end
end
end
42 changes: 42 additions & 0 deletions spec/models/mediaflux/http/asset_approve_request_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# frozen_string_literal: true
require "rails_helper"

RSpec.describe Mediaflux::Http::AssetApproveRequest, type: :model, connect_to_mediaflux: true do
let(:approver) { FactoryBot.create :sysadmin }
let(:session_id) { approver.mediaflux_session }
let(:approved_project) do
project = FactoryBot.create :approved_project
mediaflux_id = project.save_in_mediaflux(session_id: )
meta = ProjectMetadata.new(project: project, current_user: approver)
data_sponsor = User.find_by(uid: project.metadata[:data_sponsor])
project.provenance_events.create(event_type: ProvenanceEvent::SUBMISSION_EVENT_TYPE, event_person: data_sponsor.uid, event_details: "Requested by #{data_sponsor.display_name_safe}")
meta.approve_project(params: { mediaflux_id:, project_directory_prefix: "tigerns/test", project_directory: "approved_project",
storage_capacity: { size: { requested: 200, approved: 100 }, unit: { requested: "PB", approved: "TB" } },
storage_performance_expectations: { requested: "Standard", approved: "Fast" } })
project
end

let(:approve_request_xml) do
filename = Rails.root.join("spec", "fixtures", "files", "asset_approve_request.xml")
File.new(filename).read
end

let(:approve_response_xml) do
filename = Rails.root.join("spec", "fixtures", "files", "asset_approve_response.xml")
File.new(filename).read
end

describe "#resolve" do
it "updates the submission" do
approve_request = described_class.new(session_token: session_id, project: approved_project)
approve_request.resolve
req = Mediaflux::Http::AssetMetadataRequest.new(session_token: session_id, id: approved_project.mediaflux_id)
metadata = req.metadata
expect(req.error?).to be_falsey
approval = approved_project.provenance_events.find_by(event_type: ProvenanceEvent::APPROVAL_EVENT_TYPE)
expect(metadata[:submission][:approved_by]).to eq(approval.event_person)
submission = approved_project.provenance_events.find_by(event_type: ProvenanceEvent::SUBMISSION_EVENT_TYPE)
expect(metadata[:submission][:requested_by]).to eq(submission.event_person)
end
end
end
6 changes: 4 additions & 2 deletions spec/models/project_mediaflux_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@
"requested"=>project.metadata[:storage_capacity][:size][:requested]},
"unit"=>{"approved"=>"GB", "requested"=>"GB"}},
event_note: "Other",
event_note_message: "Message filler"
event_note_message: "Message filler",
storage_performance_expectations: { "requested" => "standard" }
}
project_metadata.approve_project(params:)
session_token = current_user.mediaflux_session
Expand All @@ -134,7 +135,8 @@
"requested"=>project.metadata[:storage_capacity][:size][:requested]},
"unit"=>{"approved"=>"GB", "requested"=>"GB"}},
event_note: "Other",
event_note_message: "Message filler"
event_note_message: "Message filler",
storage_performance_expectations: { "requested" => "standard" }
}
project_metadata.approve_project(params:)
session_token = current_user.mediaflux_session
Expand Down
4 changes: 4 additions & 0 deletions spec/models/project_metadata_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@
storage_capacity: {"size"=>{"approved"=>600,
"requested"=>project.metadata[:storage_capacity][:size][:requested]},
"unit"=>{"approved"=>"GB", "requested"=>"GB"}},
storage_performance_expectations: { requested: "Standard", approved: "Fast" },
event_note: "Other",
event_note_message: "Message filler"
}
Expand All @@ -169,6 +170,7 @@
storage_capacity: {"size"=>{"approved"=>600,
"requested"=>project.metadata[:storage_capacity][:size][:requested]},
"unit"=>{"approved"=>"GB", "requested"=>"GB"}},
storage_performance_expectations: { requested: "Standard", approved: "Fast" },
event_note: "Other",
event_note_message: "Message filler"
}
Expand All @@ -194,6 +196,7 @@
storage_capacity: {"size"=>{"approved"=>600,
"requested"=>project.metadata[:storage_capacity][:size][:requested]},
"unit"=>{"approved"=>"GB", "requested"=>"GB"}},
storage_performance_expectations: { requested: "Standard", approved: "Fast" },
event_note: "Other",
event_note_message: "Message filler"
}
Expand Down Expand Up @@ -244,6 +247,7 @@
storage_capacity: {"size"=>{"approved"=>600,
"requested"=>project.metadata[:storage_capacity][:size][:requested]},
"unit"=>{"approved"=>"GB", "requested"=>"GB"}},
storage_performance_expectations: { requested: "Standard", approved: "Fast" },
event_note: "Other",
event_note_message: "Message filler"
}
Expand Down

0 comments on commit e18fd9f

Please sign in to comment.