From acba7141d68f37e9f441a7ed5fb74286038a4b88 Mon Sep 17 00:00:00 2001
From: Jaymee Hyppolite <54775395+JaymeeH@users.noreply.github.com>
Date: Fri, 3 May 2024 07:36:15 -0400
Subject: [PATCH] Refine the project approval page for System Administrators
(#673)
---
app/assets/stylesheets/_settings.scss | 96 +++++++++++++++++++
app/controllers/projects_controller.rb | 20 +++-
app/models/project_metadata.rb | 7 +-
app/views/projects/_approve_form.html.erb | 39 +++++++-
app/views/projects/approve.html.erb | 33 ++++++-
...5208_add_event_note_to_provenance_event.rb | 5 +
db/schema.rb | 3 +-
spec/factories/provenance_event.rb | 8 ++
spec/models/project_mediaflux_spec.rb | 18 +++-
spec/models/project_metadata_spec.rb | 29 +++++-
spec/models/provenance_event_spec.rb | 7 ++
spec/system/project_roles_spec.rb | 4 +-
spec/system/project_spec.rb | 8 ++
13 files changed, 258 insertions(+), 19 deletions(-)
create mode 100644 db/migrate/20240502205208_add_event_note_to_provenance_event.rb
diff --git a/app/assets/stylesheets/_settings.scss b/app/assets/stylesheets/_settings.scss
index 546c3249..cce046e0 100644
--- a/app/assets/stylesheets/_settings.scss
+++ b/app/assets/stylesheets/_settings.scss
@@ -202,3 +202,99 @@
margin-top: 1em;
}
}
+
+#approve{
+ .details{
+ margin-left: 2em;
+ }
+ .provenance{
+ display: inline-block;
+ margin-right: 23em;
+ margin-left: 23.5em;
+ }
+ .field{
+ display: inline-flex;
+ margin-bottom: 2em;
+ }
+ .form-directory{
+ min-width: 13em;
+ }
+ .form-directory-confirm{
+ margin-left: 1em;
+ min-width: fit-content;
+ }
+ .form-message{
+ min-width: 15em;
+ min-height: 3em;
+ margin-left: 5px;
+ }
+ .form-date{
+ min-width: 14em;
+ }
+ .form-dropdown{
+ max-width: fit-content;
+ margin-right: 1em;
+ }
+ h2 {// Heading for the details div
+ margin-left: 0.2em;
+ text-decoration: underline;
+ text-decoration-thickness: 3px;
+ .btn.btn-primary.btn-sm{
+ margin-left: 1.5em;
+ }
+ }
+ dl {
+ width: 100%;
+ overflow: hidden;
+ padding: 0;
+ margin: 0
+ }
+ dt {
+ float: left;
+ min-width: calc(25% + 5em);
+ /* adjust the width; make sure the total of both is 100% */
+ padding: 0;
+ margin: 0;
+ margin-left: 1em;
+ clear: both
+ }
+ dd{
+ margin-bottom: .5rem;
+
+
+ }
+ p {
+ margin-left: 1em;
+ }
+ label{
+ margin-right: 5em;
+ max-width: 8em;
+ font-weight: bold;
+ }
+ input{
+ .placeholder{
+ opacity: 1;
+ }
+ -webkit-outer-spin-button, -webkit-inner-spin-button {
+ display: none;
+ margin: 0;
+ }
+ [type=number]{
+ -moz-appearance:textfield;
+ }
+ width: 10em;
+ max-height: 38px;
+ margin-right: 5px;
+ }
+ select{
+ max-height: 38px;
+ }
+ button{
+ min-width: 160px;
+ min-height: 38px
+ }
+ a{
+ min-width: 160px;
+ min-height: 38px
+ }
+}
\ No newline at end of file
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 43aea663..27dc6135 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -122,7 +122,19 @@ def update
if params.key?("mediaflux_id")
project_metadata = ProjectMetadata.new(project: project, current_user:)
project_params = params.dup
- project_metadata.approve_project(params: project_params)
+ metadata_params = project_params.merge({
+ directory: project_params["project_directory"],
+ storage_capacity: {"size"=>{"approved"=>project_params["storage_capacity"].to_i,
+ "requested"=>project.metadata[:storage_capacity][:size][:requested]},
+ "unit"=>{"approved"=>"GB", "requested"=>"GB"}},
+ approval_note: {
+ note_by: current_user.uid,
+ note_date_time: Time.current.in_time_zone("America/New_York").iso8601,
+ event_type: project_params[:event_note],
+ message: project_params[:event_note_message]
+ }
+ })
+ project_metadata.approve_project(params: metadata_params)
end
#Edit action
@@ -198,6 +210,12 @@ def file_list_download
def approve
if current_user.eligible_sysadmin?
project
+ @departments = project.departments.join(", ")
+ @project_metadata = project.metadata
+ sponsor_uid = @project_metadata[:data_sponsor]
+ @data_sponsor = User.find_by(uid: sponsor_uid)
+ @provenance_events = project.provenance_events.where.not(event_type: ProvenanceEvent::STATUS_UPDATE_EVENT_TYPE)
+
@project_metadata = project.metadata
@title = @project_metadata["title"]
else redirect_to root_path
diff --git a/app/models/project_metadata.rb b/app/models/project_metadata.rb
index 45e91538..fb52a3dc 100644
--- a/app/models/project_metadata.rb
+++ b/app/models/project_metadata.rb
@@ -53,10 +53,13 @@ def approve_project(params:)
# approve a project by recording the mediaflux id & setting the status to 'approved'
project.mediaflux_id = params[:mediaflux_id]
project.metadata_json["status"] = Project::APPROVED_STATUS
- project.save!
+ project.metadata_json["directory"] = params[:directory]
+ project.metadata_json["storage_capacity"] = params[:storage_capacity]
+ project.save!
# 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}")
+ 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])
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
diff --git a/app/views/projects/_approve_form.html.erb b/app/views/projects/_approve_form.html.erb
index c1b757ab..a999b52d 100644
--- a/app/views/projects/_approve_form.html.erb
+++ b/app/views/projects/_approve_form.html.erb
@@ -2,7 +2,40 @@
<%= render 'data_list' %>
diff --git a/app/views/projects/approve.html.erb b/app/views/projects/approve.html.erb
index 044616bf..9e94ddf8 100644
--- a/app/views/projects/approve.html.erb
+++ b/app/views/projects/approve.html.erb
@@ -1,6 +1,31 @@
+
Project Approval: <%=@title%>
-Approve this project by appending a mediaflux id
-<%= form_with url: project_path(@project), method: :put do |form| %>
- <%= render "approve_form" %>
-<% end %>
\ No newline at end of file
+
+
Metadata Highlights
+
+ - Data Sponsor
- <%= @data_sponsor.display_name_safe %>
+ - Affiliated Department(s)
- <%= @departments %>
+ - Project Directory
- <%= Rails.configuration.mediaflux["api_root_ns"] %>/<%= @project.metadata[:directory] %>
+ - Title
- <%=@project.metadata[:title] %>
+ - Project ID
- <%= @project.metadata[:project_id] %>
+ - Storage Capacity - Request
- <%= "#{@project.metadata[:storage_capacity][:size][:requested]} #{@project.metadata[:storage_capacity][:unit][:requested]}" %>
+
+
+ Submission
+
+ <% @provenance_events.each do |event| %>
+ - <%= event.event_details %>, <%=event.created_at.to_time.in_time_zone("America/New_York").iso8601%>
+ <% end %>
+
+
+
+
+
+
Project Approval Confirmation Information
+ <%= form_with url: project_path(@project), method: :put do |form| %>
+ <%= render "approve_form" %>
+ <% end %>
+
+
+
\ No newline at end of file
diff --git a/db/migrate/20240502205208_add_event_note_to_provenance_event.rb b/db/migrate/20240502205208_add_event_note_to_provenance_event.rb
new file mode 100644
index 00000000..88638e0b
--- /dev/null
+++ b/db/migrate/20240502205208_add_event_note_to_provenance_event.rb
@@ -0,0 +1,5 @@
+class AddEventNoteToProvenanceEvent < ActiveRecord::Migration[7.0]
+ def change
+ add_column :provenance_events, :event_note, :jsonb
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 103dc856..b6551d5d 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.0].define(version: 2024_02_15_181455) do
+ActiveRecord::Schema[7.0].define(version: 2024_05_02_205208) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -28,6 +28,7 @@
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "project_id"
+ t.jsonb "event_note"
t.index ["project_id"], name: "index_project_id"
end
diff --git a/spec/factories/provenance_event.rb b/spec/factories/provenance_event.rb
index 1c53db79..2b7b8975 100644
--- a/spec/factories/provenance_event.rb
+++ b/spec/factories/provenance_event.rb
@@ -10,6 +10,14 @@
factory :approval_event do
event_type { ProvenanceEvent::APPROVAL_EVENT_TYPE }
event_details { "The project was approved by #{FFaker::Name.name}" }
+ event_note do
+ {
+ NoteBy: FFaker::Name.name.to_s,
+ NoteDateTime: Time.current.in_time_zone("America/New_York").iso8601,
+ EventType: "Other",
+ Message: "Filler Message"
+ }
+ end
end
factory :status_update_event do
event_type { ProvenanceEvent::STATUS_UPDATE_EVENT_TYPE }
diff --git a/spec/models/project_mediaflux_spec.rb b/spec/models/project_mediaflux_spec.rb
index faa6faeb..c07ac50c 100644
--- a/spec/models/project_mediaflux_spec.rb
+++ b/spec/models/project_mediaflux_spec.rb
@@ -86,7 +86,14 @@
Mediaflux::Http::AssetDestroyRequest.new(session_token: current_user.mediaflux_session, collection: incomplete_project.mediaflux_id, members: true).resolve
end
it "should raise a MetadataError if any required is missing" do
- params = {mediaflux_id: 001}
+ params = {mediaflux_id: 001,
+ directory: incomplete_project.metadata[:directory],
+ storage_capacity: {"size"=>{"approved"=>600,
+ "requested"=>project.metadata[:storage_capacity][:size][:requested]},
+ "unit"=>{"approved"=>"GB", "requested"=>"GB"}},
+ event_note: "Other",
+ event_note_message: "Message filler"
+ }
project_metadata.approve_project(params:)
session_token = current_user.mediaflux_session
@@ -103,7 +110,14 @@
end
it "should raise a error if any error occurs in mediaflux" do
- params = {mediaflux_id: 001}
+ params = {mediaflux_id: 001,
+ directory: incomplete_project.metadata[:directory],
+ storage_capacity: {"size"=>{"approved"=>600,
+ "requested"=>project.metadata[:storage_capacity][:size][:requested]},
+ "unit"=>{"approved"=>"GB", "requested"=>"GB"}},
+ event_note: "Other",
+ event_note_message: "Message filler"
+ }
project_metadata.approve_project(params:)
session_token = current_user.mediaflux_session
diff --git a/spec/models/project_metadata_spec.rb b/spec/models/project_metadata_spec.rb
index 48871673..01f6caff 100644
--- a/spec/models/project_metadata_spec.rb
+++ b/spec/models/project_metadata_spec.rb
@@ -147,7 +147,14 @@
describe "#approve_project" do
it "Records the mediaflux id and sets the status to approved" do
project_metadata = described_class.new(current_user: current_user, project:)
- params = {mediaflux_id: 001 }
+ params = {mediaflux_id: 001,
+ directory: project.metadata[:directory],
+ storage_capacity: {"size"=>{"approved"=>600,
+ "requested"=>project.metadata[:storage_capacity][:size][:requested]},
+ "unit"=>{"approved"=>"GB", "requested"=>"GB"}},
+ event_note: "Other",
+ event_note_message: "Message filler"
+ }
project_metadata.approve_project(params:)
project.reload
@@ -157,8 +164,15 @@
end
it "Creates a Provenance Event: Approval" do
project_metadata = described_class.new(current_user: current_user, project:)
- params = {data_sponsor: "abc", data_manager: "def", departments: "dep", directory: "dir", title: "title abc", description: "description 123" }
- project_metadata.approve_project(params: {}) # doesn't call the doi service twice
+ params = {mediaflux_id: 001,
+ directory: project.metadata[:directory],
+ storage_capacity: {"size"=>{"approved"=>600,
+ "requested"=>project.metadata[:storage_capacity][:size][:requested]},
+ "unit"=>{"approved"=>"GB", "requested"=>"GB"}},
+ event_note: "Other",
+ event_note_message: "Message filler"
+ }
+ project_metadata.approve_project(params:) # doesn't call the doi service twice
project.reload
expect(project.provenance_events.count).to eq 2
@@ -176,7 +190,14 @@
Mediaflux::Http::AssetDestroyRequest.new(session_token: current_user.mediaflux_session, collection: valid_project.mediaflux_id, members: true).resolve
end
it "validates the doi for a project" do
- params = {mediaflux_id: 001 }
+ params = {mediaflux_id: 001,
+ directory: valid_project.metadata[:directory],
+ storage_capacity: {"size"=>{"approved"=>600,
+ "requested"=>project.metadata[:storage_capacity][:size][:requested]},
+ "unit"=>{"approved"=>"GB", "requested"=>"GB"}},
+ event_note: "Other",
+ event_note_message: "Message filler"
+ }
project_metadata.approve_project(params:)
#create a project in mediaflux
diff --git a/spec/models/provenance_event_spec.rb b/spec/models/provenance_event_spec.rb
index bf3b43c0..89d4b469 100644
--- a/spec/models/provenance_event_spec.rb
+++ b/spec/models/provenance_event_spec.rb
@@ -18,8 +18,15 @@
pe.event_type = ProvenanceEvent::APPROVAL_EVENT_TYPE
pe.event_details = "Approved by Jane Doe, 2023-01-19T12:00:00"
pe.event_person = "abc123"
+ pe.event_note = {
+ NoteBy: pe.event_person,
+ NoteDateTime: pe.created_at,
+ EventType: "Other",
+ Message: "Approval Note"
+ }
pe.save
expect(pe.event_type).to eq(ProvenanceEvent::APPROVAL_EVENT_TYPE)
+ expect(pe.event_note).not_to eq nil
end
end
context "when a project is approved" do
diff --git a/spec/system/project_roles_spec.rb b/spec/system/project_roles_spec.rb
index 5ee067ff..6f78026c 100644
--- a/spec/system/project_roles_spec.rb
+++ b/spec/system/project_roles_spec.rb
@@ -219,14 +219,14 @@
sign_in system_admin
visit project_approve_path(project)
click_on "Approve"
- expect(page).to have_content "Approve this project by appending a mediaflux id"
+ expect(page).to have_content "Metadata Highlights"
end
it "allows a super user to approve the project" do
sign_in superuser
visit project_approve_path(project)
click_on "Approve"
- expect(page).to have_content "Approve this project by appending a mediaflux id"
+ expect(page).to have_content "Metadata Highlights"
end
it "does not allow a data sponsor to approve the project" do
diff --git a/spec/system/project_spec.rb b/spec/system/project_spec.rb
index f7fc1827..e606a906 100644
--- a/spec/system/project_spec.rb
+++ b/spec/system/project_spec.rb
@@ -437,7 +437,11 @@
visit project_approve_path(project)
expect(page).to have_content("Project Approval: #{project.metadata_json['title']}")
+ fill_in "storage_capacity", with: 500
+ fill_in "project_directory", with: project.metadata_json["directory"]
fill_in "mediaflux_id", with: mediaflux_id
+ select "Other", :from => "event_note"
+ fill_in "event_note_message", with: "Note from sysadmin"
click_on "Approve"
project.reload
@@ -455,7 +459,11 @@
visit project_approve_path(project)
expect(page).to have_content("Project Approval: #{project.metadata_json['title']}")
+ fill_in "storage_capacity", with: 500
+ fill_in "project_directory", with: project.metadata_json["directory"]
fill_in "mediaflux_id", with: mediaflux_id
+ select "Other", :from => "event_note"
+ fill_in "event_note_message", with: "Note from sysadmin"
click_on "Approve"
# This is the confirmation page. It needs a button to return to the dashboard