From d18a54c87433b91455e3dab51a8b8c48261e079b Mon Sep 17 00:00:00 2001
From: aignatov-bio <47317017+aignatov-bio@users.noreply.github.com>
Date: Tue, 20 Apr 2021 13:35:40 +0200
Subject: [PATCH] Update create and update action for reports controller
[SCI-5641] (#3260)
Update create and update action [SCI-5641]
---
app/assets/javascripts/reports/new.js | 70 ++++++--
.../reports/checkbox_input_component.html.erb | 2 +-
.../reports/date_input_component.html.erb | 2 +-
.../large_text_input_component.html.erb | 2 +-
.../multi_checkbox_input_component.html.erb | 2 +-
.../team_member_input_component.html.erb | 2 +-
.../reports/text_input_component.html.erb | 2 +-
app/controllers/reports_controller.rb | 65 ++++----
app/models/report.rb | 44 +----
app/services/report_actions/report_content.rb | 157 ++++++++++++++++++
.../_my_module_activity_element.html.erb | 3 +-
.../_my_module_repository_element.html.erb | 3 +-
.../elements/_step_comments_element.html.erb | 3 +-
app/views/reports/new.html.erb | 4 +-
.../reports/wizard/_second_step.html.erb | 2 +-
config/routes.rb | 2 +-
16 files changed, 253 insertions(+), 112 deletions(-)
create mode 100644 app/services/report_actions/report_content.rb
diff --git a/app/assets/javascripts/reports/new.js b/app/assets/javascripts/reports/new.js
index b02ac0364..63dc46a60 100644
--- a/app/assets/javascripts/reports/new.js
+++ b/app/assets/javascripts/reports/new.js
@@ -972,8 +972,11 @@ function reportHandsonTableConverter() {
var reportData = {};
// Report name
- reportData.name = $('.report-name').val();
-
+ reportData.report = {
+ name: $('.report-name').val(),
+ description: $('#projectDescription').val(),
+ settings: { task: { protocol: {} } }
+ };
// Project
reportData.project_id = dropdownSelector.getValues('#projectSelector');
@@ -983,19 +986,30 @@ function reportHandsonTableConverter() {
// Template values
reportData.template_values = {};
$.each($('.report-template-values-container').find('.sci-input-field, select'), function(i, field) {
- reportData.template_values[field.name] = field.value;
+ if (field.value.length === 0) return;
+
+ reportData.template_values[field.name] = {
+ value: field.value,
+ view_component: field.dataset.type
+ };
});
$.each($('.report-template-values-container .sci-checkbox'), function(i, checkbox) {
if (checkbox.name.includes('[]')) {
let name = checkbox.name.replace('[]', '');
if (!reportData.template_values[name]) {
- reportData.template_values[name] = {};
+ reportData.template_values[name] = {
+ value: {},
+ view_component: checkbox.dataset.type
+ };
}
reportData
- .template_values[name][checkbox.value] = checkbox.checked;
+ .template_values[name].value[checkbox.value] = checkbox.checked;
} else {
- reportData.template_values[checkbox.name] = checkbox.checked;
+ reportData.template_values[checkbox.name] = {
+ value: checkbox.checked,
+ view_component: checkbox.dataset.type
+ };
}
});
@@ -1003,8 +1017,8 @@ function reportHandsonTableConverter() {
reportData.project_content = [];
$.each($('.project-contents-container .experiment-element'), function(i, experiment) {
let experimentHash = {};
-
- if (!$(experiment).find('.report-experiment-checkbox').prop('checked')) return;
+ let expCheckbox = $(experiment).find('.report-experiment-checkbox');
+ if (!expCheckbox.prop('checked') && !expCheckbox.prop('indeterminate')) return;
experimentHash.experiment_id = $(experiment).find('.report-experiment-checkbox').val();
experimentHash.my_modules = [];
@@ -1015,15 +1029,21 @@ function reportHandsonTableConverter() {
});
// Settings
- reportData.settings = { task: { protocol: {} } };
- reportData.settings.all_tasks = $('.task-contents-container .select-all-task-contents').prop('checked');
+ if ($('.project-contents-container .select-all-my-modules-checkbox').prop('checked')) {
+ reportData.report.settings.all_tasks = $('.project-contents-container .select-all-my-modules-checkbox')
+ .prop('checked');
+ }
$.each($('.task-contents-container .content-element .protocol-setting'), function(i, e) {
- reportData.settings.task.protocol[e.value] = e.checked;
+ if (e.checked) {
+ reportData.report.settings.task.protocol[e.value] = e.checked;
+ }
});
$.each($('.task-contents-container .content-element .task-setting'), function(i, e) {
- reportData.settings.task[e.value] = e.checked;
+ if (e.checked) {
+ reportData.report.settings.task[e.value] = e.checked;
+ }
});
- reportData.settings.task.result_order = dropdownSelector.getValues('#taskResultsOrder');
+ reportData.report.settings.task.result_order = dropdownSelector.getValues('#taskResultsOrder');
return reportData;
}
@@ -1034,6 +1054,25 @@ function reportHandsonTableConverter() {
// TODO
});
});
+
+ $('.reports-new').on('click', '#saveAsNewReport', function(e) {
+ var params = getReportData();
+ params.report.name = 'New ' + params.report.name;
+ e.preventDefault();
+ $.post(this.dataset.createUrl, params, function() {
+ // TODO
+ });
+ });
+
+
+ $('.reports-new').on('click', '#UpdateReport', function(e) {
+ e.preventDefault();
+ $.ajax({
+ type: 'PUT',
+ url: this.dataset.updateUrl,
+ data: getReportData()
+ });
+ });
}
function initReportWizard() {
@@ -1070,8 +1109,8 @@ function reportHandsonTableConverter() {
$('.reports-new-body [href="#new-report-step-2"]').on('show.bs.tab', function() {
var projectContents = $('#new-report-step-2').find('.project-contents');
- if (projectContents.is(':empty')) {
- let projectId = dropdownSelector.getValues('#projectSelector');
+ var projectId = dropdownSelector.getValues('#projectSelector');
+ if (projectContents.data('project-id') !== parseInt(projectId, 10)) {
animateSpinner('.reports-new-body');
$.get(projectContents.data('project-content-url'), { project_id: projectId }, function(data) {
animateSpinner('.reports-new-body', false);
@@ -1169,7 +1208,6 @@ function reportHandsonTableConverter() {
noEmptyOption: true,
selectAppearance: 'simple',
onChange: function() {
- $('#new-report-step-2 .project-contents').empty();
$('.continue-button').attr('disabled', false);
}
});
diff --git a/app/components/reports/checkbox_input_component.html.erb b/app/components/reports/checkbox_input_component.html.erb
index d52de0c6b..b25d5f36b 100644
--- a/app/components/reports/checkbox_input_component.html.erb
+++ b/app/components/reports/checkbox_input_component.html.erb
@@ -1,6 +1,6 @@
- <%= check_box_tag @name, true, false, class: 'sci-checkbox' %>
+ <%= check_box_tag @name, true, (@value == 'true'), class: 'sci-checkbox', data: { type: 'CheckboxInputComponent' } %>
<%= @label %>
diff --git a/app/components/reports/date_input_component.html.erb b/app/components/reports/date_input_component.html.erb
index 1c0fd5c28..ba9fd8ad5 100644
--- a/app/components/reports/date_input_component.html.erb
+++ b/app/components/reports/date_input_component.html.erb
@@ -1,7 +1,7 @@
<% if @editing %>
<%= label_tag @name, @label %>
- <%= date_field_tag @name, @value, placeholder: @placeholder, class: 'sci-input-field' %>
+ <%= date_field_tag @name, @value, placeholder: @placeholder, class: 'sci-input-field', data: { type: 'DateInputComponent' } %>
<% else %>
<%= @value %>
diff --git a/app/components/reports/large_text_input_component.html.erb b/app/components/reports/large_text_input_component.html.erb
index 7d2d5a063..820dc5b60 100644
--- a/app/components/reports/large_text_input_component.html.erb
+++ b/app/components/reports/large_text_input_component.html.erb
@@ -1,7 +1,7 @@
<% if @editing %>
<%= label_tag @name, @label %>
- <%= text_area_tag @name, @value, placeholder: @placeholder, class: 'sci-input-field' %>
+ <%= text_area_tag @name, @value, placeholder: @placeholder, class: 'sci-input-field', data: { type: 'LargeTextInputComponent' } %>
<% else %>
<%= @value %>
diff --git a/app/components/reports/multi_checkbox_input_component.html.erb b/app/components/reports/multi_checkbox_input_component.html.erb
index 01ba36d2b..98ff08ff9 100644
--- a/app/components/reports/multi_checkbox_input_component.html.erb
+++ b/app/components/reports/multi_checkbox_input_component.html.erb
@@ -4,7 +4,7 @@
<% @items.each do |key, value| %>
- <%= check_box_tag "#{@name}[]", key, false ,class: 'sci-checkbox' %>
+ <%= check_box_tag "#{@name}[]", key, (@value && @value[key.to_s] == 'true') ,class: 'sci-checkbox', data: { type: 'MultiCheckboxInputComponent' } %>
<%= value %>
diff --git a/app/components/reports/team_member_input_component.html.erb b/app/components/reports/team_member_input_component.html.erb
index 8f2476d2f..4ef7722d7 100644
--- a/app/components/reports/team_member_input_component.html.erb
+++ b/app/components/reports/team_member_input_component.html.erb
@@ -1,7 +1,7 @@
<% if @editing %>
<%= label_tag @name, @label %>
- <%= select_tag @name, options_from_collection_for_select(@team_members, :id, :name), placeholder: @placeholder, class: 'sci-input-field' %>
+ <%= select_tag @name, options_from_collection_for_select(@team_members, :id, :name), placeholder: @placeholder, class: 'sci-input-field', data: { type: 'TeamMemberInputComponent' } %>
<% else %>
<%= @value %>
diff --git a/app/components/reports/text_input_component.html.erb b/app/components/reports/text_input_component.html.erb
index 4d7cb2390..eb5dbecb9 100644
--- a/app/components/reports/text_input_component.html.erb
+++ b/app/components/reports/text_input_component.html.erb
@@ -1,7 +1,7 @@
<% if @editing %>
<%= label_tag @name, @label %>
- <%= text_field_tag @name, @value, placeholder: @placeholder, class: 'sci-input-field input-large' %>
+ <%= text_field_tag @name, @value, placeholder: @placeholder, class: 'sci-input-field input-large', data: { type: 'TextInputComponent' } %>
<% else %>
<%= @value %>
diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb
index d118e2b61..4ddb66816 100644
--- a/app/controllers/reports_controller.rb
+++ b/app/controllers/reports_controller.rb
@@ -1,6 +1,7 @@
class ReportsController < ApplicationController
include TeamsHelper
include ReportActions
+ include ReportsHelper
BEFORE_ACTION_METHODS = %i(
create
@@ -29,6 +30,8 @@ class ReportsController < ApplicationController
before_action :check_manage_permissions, only: BEFORE_ACTION_METHODS
before_action :switch_team_with_param, only: :index
+ after_action :generate_pdf_report, only: %i(create update)
+
# Index showing all reports of a single project
def index; end
@@ -75,33 +78,25 @@ class ReportsController < ApplicationController
# Creating new report from the _save modal of the new page
def create
- continue = true
- begin
- report_contents = JSON.parse(params.delete(:report_contents))
- rescue
- continue = false
- end
-
@report = Report.new(report_params)
@report.project = @project
@report.user = current_user
@report.team = current_team
+ @report.settings = report_params[:settings]
@report.last_modified_by = current_user
+ @report = ReportActions::ReportContent.new(
+ @report,
+ params[:project_content],
+ params[:template_values],
+ current_user
+ ).save_with_content
- if continue && @report.save_with_contents(report_contents)
+ if @report
log_activity(:create_report)
- respond_to do |format|
- format.json do
- render json: { url: reports_path }, status: :ok
- end
- end
+ redirect_to reports_path
else
- respond_to do |format|
- format.json do
- render json: @report.errors, status: :unprocessable_entity
- end
- end
+ render json: @report.errors, status: :unprocessable_entity
end
end
@@ -117,30 +112,22 @@ class ReportsController < ApplicationController
# Updating existing report from the _save modal of the new page
def update
- continue = true
- begin
- report_contents = JSON.parse(params.delete(:report_contents))
- rescue
- continue = false
- end
-
@report.last_modified_by = current_user
@report.assign_attributes(report_params)
- if continue && @report.save_with_contents(report_contents)
+ @report = ReportActions::ReportContent.new(
+ @report,
+ params[:project_content],
+ params[:template_values],
+ current_user
+ ).save_with_content
+
+ if @report
log_activity(:edit_report)
- respond_to do |format|
- format.json do
- render json: { url: reports_path }, status: :ok
- end
- end
+ redirect_to reports_path
else
- respond_to do |format|
- format.json do
- render json: @report.errors, status: :unprocessable_entity
- end
- end
+ render json: @report.errors, status: :unprocessable_entity
end
end
@@ -531,7 +518,7 @@ class ReportsController < ApplicationController
def report_params
params.require(:report)
- .permit(:name, :description, :grouped_by, :report_contents)
+ .permit(:name, :description, :grouped_by, :report_contents, settings: {})
end
def search_params
@@ -551,4 +538,8 @@ class ReportsController < ApplicationController
project: report.project,
message_items: { report: report.id })
end
+
+ def generate_pdf_report
+ Reports::PdfJob.perform_later(@report, 'template_1', current_user) if @report.persisted?
+ end
end
diff --git a/app/models/report.rb b/app/models/report.rb
index eb7ce912e..c9cb67f86 100644
--- a/app/models/report.rb
+++ b/app/models/report.rb
@@ -48,7 +48,7 @@ class Report < ApplicationRecord
table_results: true,
text_results: true,
result_comments: true,
- result_order: "atoz",
+ result_order: 'atoz',
activities: true
}
}.freeze
@@ -91,28 +91,6 @@ class Report < ApplicationRecord
report_elements.order(:position).select { |el| el.parent.blank? }
end
- # Save the JSON represented contents to this report
- # (this action will overwrite any existing report elements)
- def save_with_contents(json_contents)
- begin
- Report.transaction do
- # First, save the report itself
- save!
-
- # Secondly, delete existing report elements
- report_elements.destroy_all
-
- # Lastly, iterate through contents
- json_contents.each_with_index do |json_el, i|
- save_json_element(json_el, i, nil)
- end
- end
- rescue ActiveRecord::ActiveRecordError, ArgumentError
- return false
- end
- true
- end
-
# Clean report elements from report
# the function runs before the report is edit
def cleanup_report
@@ -160,24 +138,4 @@ class Report < ApplicationRecord
end
elements
end
-
- private
-
- # Recursively save a single JSON element
- def save_json_element(json_element, index, parent)
- el = ReportElement.new
- el.position = index
- el.report = self
- el.parent = parent
- el.type_of = json_element['type_of']
- el.sort_order = json_element['sort_order']
- el.set_element_references(json_element['id'])
- el.save!
-
- if json_element['children'].present?
- json_element['children'].each_with_index do |child, i|
- save_json_element(child, i, el)
- end
- end
- end
end
diff --git a/app/services/report_actions/report_content.rb b/app/services/report_actions/report_content.rb
new file mode 100644
index 000000000..440a3e839
--- /dev/null
+++ b/app/services/report_actions/report_content.rb
@@ -0,0 +1,157 @@
+# frozen_string_literal: true
+
+module ReportActions
+ class ReportContent
+ include Canaid::Helpers::PermissionsHelper
+
+ MY_MODULE_ADDONS_ELEMENTS = []
+
+ def initialize(report, content, template_values, user)
+ @content = content
+ @settings = report.settings
+ @user = user
+ @element_position = 0
+ @report = report
+ @template_values = template_values
+ end
+
+ def save_with_content
+ Report.transaction do
+ # Save the report itself
+ @report.save!
+
+ # Delete existing report elements
+ @report.report_elements.destroy_all
+
+ # Save new report elements
+ generate_content
+
+ # Delete existing template values
+ @report.report_template_values.destroy_all
+
+ formatted_template_values = @template_values.as_json.map { |k, v| v['name'] = k; v }
+ # Save new template values
+ @report.report_template_values.create!(formatted_template_values)
+ end
+
+ @report
+ rescue ActiveRecord::ActiveRecordError, ArgumentError => e
+ Rails.logger.error e.message
+ raise ActiveRecord::Rollback
+ end
+
+ private
+
+ def generate_content
+ @content.each do |_i, exp|
+ generate_experiment_content(exp)
+ end
+ end
+
+ def generate_experiment_content(exp)
+ experiment = Experiment.find_by(id: exp[:experiment_id])
+ return if !experiment && !can_read_experiment?(experiment, @user)
+
+ experiment_element = save_element({ 'experiment_id' => experiment.id }, :experiment, nil)
+ generate_my_modules_content(experiment, experiment_element, exp[:my_modules])
+ end
+
+ def generate_my_modules_content(experiment, experiment_element, selected_my_modules)
+ my_modules = experiment.my_modules
+ .active
+ .includes(:results, protocols: [:steps])
+ .where(id: selected_my_modules)
+ my_modules.sort_by { |m| selected_my_modules.index m.id }.each do |my_module|
+ my_module_element = save_element({ 'my_module_id' => my_module.id }, :my_module, experiment_element)
+
+ if @settings.dig('task', 'protocol', 'description')
+ save_element({ 'my_module_id' => my_module.id }, :my_module_protocol, my_module_element)
+ end
+
+ generate_steps_content(my_module, my_module_element)
+
+ generate_results_content(my_module, my_module_element)
+
+ if @settings.dig('task', 'activities')
+ save_element({ 'my_module_id' => my_module.id }, :my_module_activity, my_module_element)
+
+ end
+
+ my_module.experiment.project.assigned_repositories_and_snapshots.each do |repository|
+ save_element(
+ { 'my_module_id' => my_module.id, 'repository_id' => repository.id },
+ :my_module_repository,
+ my_module_element
+ )
+ end
+
+ MY_MODULE_ADDONS_ELEMENTS.each do |e|
+ send("generate_#{e}_content", my_module, my_module_element)
+ end
+ end
+ end
+
+ def generate_steps_content(my_module, my_module_element)
+ my_module.protocols.first.steps
+ .includes(:checklists, :step_tables, :step_assets, :step_comments)
+ .order(:position).each do |step|
+ step_element = nil
+ if step.completed && @settings.dig('task', 'protocol', 'completed_steps')
+ step_element = save_element({ 'step_id' => step.id }, :step, my_module_element)
+ elsif @settings.dig('task', 'protocol', 'uncompleted_steps')
+ step_element = save_element({ 'step_id' => step.id }, :step, my_module_element)
+ end
+
+ next unless step_element
+
+ if @settings.dig('task', 'protocol', 'step_checklists')
+ step.checklists.each do |checklist|
+ save_element({ 'checklist_id' => checklist.id }, :step_checklist, step_element)
+ end
+ end
+
+ if @settings.dig('task', 'protocol', 'step_tables')
+ step.step_tables.each do |table|
+ save_element({ 'table_id' => table.id }, :step_table, step_element)
+ end
+ end
+
+ if @settings.dig('task', 'protocol', 'step_files')
+ step.step_assets.each do |asset|
+ save_element({ 'asset_id' => asset.id }, :step_asset, step_element)
+ end
+ end
+
+ if @settings.dig('task', 'protocol', 'step_comments')
+ save_element({ 'step_id' => step.id }, :step_comments, step_element)
+ end
+ end
+ end
+
+ def generate_results_content(my_module, my_module_element)
+ my_module.results do |result|
+ result_type = (result.result_asset || result.result_table || result.result_text).class.to_s.underscore
+
+ next unless @settings.dig('task', result_type)
+
+ result_element = save_element({ 'result_id' => result.id }, result_type, my_module_element)
+
+ save_element({ 'result_id' => result.id }, :result_comments, result_element)
+ end
+ end
+
+ def save_element(reference, type_of, parent)
+ el = ReportElement.new
+ el.position = @element_position
+ el.report = @report
+ el.parent = parent
+ el.type_of = type_of
+ el.set_element_references(reference)
+ el.save!
+
+ @element_position += 1
+
+ el
+ end
+ end
+end
diff --git a/app/views/reports/elements/_my_module_activity_element.html.erb b/app/views/reports/elements/_my_module_activity_element.html.erb
index 4208fe468..1e068c9d9 100644
--- a/app/views/reports/elements/_my_module_activity_element.html.erb
+++ b/app/views/reports/elements/_my_module_activity_element.html.erb
@@ -1,7 +1,6 @@
<% if my_module.blank? and @my_module.present? then my_module = @my_module end %>
-<% if order.blank? and @order.present? then order = @order end %>
<% timestamp = Time.current + 1.year - 2.days %>
-<% activities = ActivitiesService.my_module_activities(my_module).order(created_at: order) %>
+<% activities = ActivitiesService.my_module_activities(my_module).order(created_at: :desc) %>
" data-name="<%=t "projects.reports.elements.module_activity.sidebar_name" %>" data-icon-class="fas fa-list">