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' %>
- - - +
+ + > / + > +
+
+ + >GB +
+
+ + +
+
+ + > +
+
+ + > +
+
+ + + + +
+
+ + <%= link_to "Cancel", root_path, class: "btn btn-secondary" %> +
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 +

+

+
+ +
+

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