2020-10-14 18:12:32 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-06-23 21:19:08 +08:00
|
|
|
class Report < ApplicationRecord
|
2016-02-12 23:52:43 +08:00
|
|
|
include SearchableModel
|
2019-03-26 00:35:54 +08:00
|
|
|
include SearchableByNameModel
|
2016-02-12 23:52:43 +08:00
|
|
|
|
2016-09-21 21:35:23 +08:00
|
|
|
auto_strip_attributes :name, :description, nullify: false
|
2016-02-12 23:52:43 +08:00
|
|
|
validates :name,
|
2016-10-05 23:45:20 +08:00
|
|
|
length: { minimum: Constants::NAME_MIN_LENGTH,
|
|
|
|
maximum: Constants::NAME_MAX_LENGTH },
|
2019-05-07 19:47:50 +08:00
|
|
|
uniqueness: { scope: %i(user_id project_id), case_sensitive: false }
|
2016-10-05 23:45:20 +08:00
|
|
|
validates :description, length: { maximum: Constants::TEXT_MAX_LENGTH }
|
2016-02-12 23:52:43 +08:00
|
|
|
validates :project, presence: true
|
|
|
|
validates :user, presence: true
|
|
|
|
|
2019-07-26 18:40:36 +08:00
|
|
|
belongs_to :project, inverse_of: :reports
|
|
|
|
belongs_to :user, inverse_of: :reports
|
2018-04-18 22:47:52 +08:00
|
|
|
belongs_to :team, inverse_of: :reports
|
2017-06-28 21:21:32 +08:00
|
|
|
belongs_to :last_modified_by,
|
|
|
|
foreign_key: 'last_modified_by_id',
|
|
|
|
class_name: 'User',
|
|
|
|
optional: true
|
2016-02-12 23:52:43 +08:00
|
|
|
|
|
|
|
# Report either has many report elements (if grouped by timestamp),
|
|
|
|
# or many module elements (if grouped by module)
|
2018-09-17 02:05:13 +08:00
|
|
|
has_many :report_elements, inverse_of: :report, dependent: :delete_all
|
2016-02-12 23:52:43 +08:00
|
|
|
|
|
|
|
def self.search(
|
|
|
|
user,
|
|
|
|
include_archived,
|
|
|
|
query = nil,
|
2017-05-05 22:41:23 +08:00
|
|
|
page = 1,
|
|
|
|
_current_team = nil,
|
|
|
|
options = {}
|
2016-02-12 23:52:43 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
project_ids =
|
|
|
|
Project
|
2016-10-05 23:45:20 +08:00
|
|
|
.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
|
2017-04-11 20:55:44 +08:00
|
|
|
.pluck(:id)
|
2016-02-12 23:52:43 +08:00
|
|
|
|
2017-05-05 22:41:23 +08:00
|
|
|
new_query =
|
|
|
|
Report
|
2016-02-12 23:52:43 +08:00
|
|
|
.distinct
|
2017-05-05 22:41:23 +08:00
|
|
|
.where('reports.project_id IN (?)', project_ids)
|
2018-11-30 18:46:13 +08:00
|
|
|
.where_attributes_like(%i(name description), query, options)
|
2016-02-12 23:52:43 +08:00
|
|
|
|
|
|
|
# Show all results if needed
|
2016-10-05 23:45:20 +08:00
|
|
|
if page == Constants::SEARCH_NO_LIMIT
|
2016-02-12 23:52:43 +08:00
|
|
|
new_query
|
|
|
|
else
|
|
|
|
new_query
|
2016-10-05 23:45:20 +08:00
|
|
|
.limit(Constants::SEARCH_LIMIT)
|
|
|
|
.offset((page - 1) * Constants::SEARCH_LIMIT)
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-03-26 00:35:54 +08:00
|
|
|
def self.viewable_by_user(user, teams)
|
|
|
|
where(project: Project.viewable_by_user(user, teams))
|
2018-12-13 18:18:09 +08:00
|
|
|
end
|
|
|
|
|
2016-02-12 23:52:43 +08:00
|
|
|
def root_elements
|
2020-10-14 18:12:32 +08:00
|
|
|
report_elements.order(:position).select { |el| el.parent.blank? }
|
2016-02-12 23:52:43 +08:00
|
|
|
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
|
2020-10-14 18:12:32 +08:00
|
|
|
# First, save the report itself
|
2016-02-12 23:52:43 +08:00
|
|
|
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
|
2020-10-14 18:12:32 +08:00
|
|
|
true
|
2016-02-12 23:52:43 +08:00
|
|
|
end
|
|
|
|
|
2016-07-21 19:11:15 +08:00
|
|
|
# Clean report elements from report
|
|
|
|
# the function runs before the report is edit
|
|
|
|
def cleanup_report
|
2020-10-14 18:12:32 +08:00
|
|
|
report_elements.each(&:clean_removed_or_archived_elements)
|
2016-07-21 19:11:15 +08:00
|
|
|
end
|
|
|
|
|
2018-09-17 03:00:09 +08:00
|
|
|
def self.generate_whole_project_report(project, current_user, current_team)
|
2018-10-12 11:59:45 +08:00
|
|
|
report_contents = gen_element_content(project, nil, 'project_header', true)
|
2020-10-14 18:08:04 +08:00
|
|
|
Extends::EXPORT_ALL_PROJECT_ELEMENTS.each do |report_element, children|
|
|
|
|
report_contents += public_send("generate_#{report_element}_element", project, children)
|
2018-09-17 03:00:09 +08:00
|
|
|
end
|
|
|
|
|
2018-10-12 11:59:45 +08:00
|
|
|
report = Report.new
|
|
|
|
report.name = loop do
|
2018-09-17 03:00:09 +08:00
|
|
|
dummy_name = SecureRandom.hex(10)
|
|
|
|
break dummy_name unless Report.where(name: dummy_name).exists?
|
|
|
|
end
|
|
|
|
report.project = project
|
|
|
|
report.user = current_user
|
|
|
|
report.team = current_team
|
|
|
|
report.last_modified_by = current_user
|
|
|
|
report.save_with_contents(report_contents)
|
|
|
|
report
|
|
|
|
end
|
|
|
|
|
2018-10-12 11:59:45 +08:00
|
|
|
def self.gen_element_content(parent_obj, association_objs, type_of,
|
|
|
|
use_parent_id = false, sort_order = nil,
|
|
|
|
children = nil)
|
|
|
|
parent_type = parent_obj.class.name.underscore
|
|
|
|
type = type_of.split('_').last.singularize
|
|
|
|
extra_id_needed = use_parent_id && !association_objs.nil?
|
|
|
|
elements = []
|
|
|
|
|
|
|
|
association_objs ||= [nil]
|
|
|
|
association_objs.each do |obj|
|
|
|
|
elements << {
|
|
|
|
'type_of' => type_of,
|
|
|
|
'id' => {}.tap do |ids_hash|
|
|
|
|
if use_parent_id
|
|
|
|
ids_hash["#{parent_type}_id"] = parent_obj.id
|
|
|
|
else
|
|
|
|
ids_hash["#{type}_id"] = obj.id
|
|
|
|
end
|
|
|
|
ids_hash["#{type}_id"] = obj.id if extra_id_needed
|
|
|
|
end,
|
2020-10-14 18:12:32 +08:00
|
|
|
'sort_order' => sort_order.presence,
|
|
|
|
'children' => children.presence || []
|
2018-10-12 11:59:45 +08:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
elements
|
|
|
|
end
|
|
|
|
|
2020-10-14 18:08:04 +08:00
|
|
|
def self.generate_experiments_element(project, elements)
|
|
|
|
experiments = []
|
|
|
|
project.experiments.each do |experiment|
|
|
|
|
experiment_contents = []
|
|
|
|
elements.each do |report_element, children|
|
|
|
|
experiment_contents += public_send("generate_#{report_element}_element", experiment, children)
|
|
|
|
end
|
|
|
|
experiments += gen_element_content(experiment, nil, 'experiment', true, nil, experiment_contents)
|
|
|
|
end
|
|
|
|
experiments
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.generate_my_modules_element(experiment, elements)
|
|
|
|
my_modules = []
|
|
|
|
experiment.my_modules.each do |my_module|
|
|
|
|
my_module_contents = []
|
|
|
|
elements.each do |report_element, children|
|
|
|
|
my_module_contents += public_send("generate_#{report_element}_element", my_module, children)
|
|
|
|
end
|
|
|
|
my_modules += gen_element_content(my_module, nil, 'my_module', true, nil, my_module_contents)
|
|
|
|
end
|
|
|
|
my_modules
|
2020-10-12 21:55:06 +08:00
|
|
|
end
|
|
|
|
|
2020-10-14 18:08:04 +08:00
|
|
|
def self.generate_my_module_protocol_element(my_module, elements)
|
|
|
|
protcol_contents = []
|
|
|
|
elements.each do |report_element, children|
|
|
|
|
protcol_contents += public_send("generate_#{report_element}_element", my_module, children)
|
|
|
|
end
|
|
|
|
gen_element_content(my_module, nil, 'my_module_protocol', true, nil, protcol_contents)
|
|
|
|
end
|
2020-10-12 21:55:06 +08:00
|
|
|
|
2020-10-14 18:08:04 +08:00
|
|
|
def self.generate_my_module_steps_element(my_module, elements)
|
|
|
|
steps = []
|
|
|
|
my_module.protocol.steps.each do |step|
|
|
|
|
step_contents = []
|
|
|
|
elements.each do |report_element, children|
|
|
|
|
step_contents += public_send("generate_#{report_element}_element", step, children)
|
|
|
|
end
|
|
|
|
steps += gen_element_content(step, nil, 'step', true, nil, step_contents)
|
2020-10-12 21:55:06 +08:00
|
|
|
end
|
2020-10-14 18:08:04 +08:00
|
|
|
steps
|
|
|
|
end
|
|
|
|
|
2020-10-14 18:12:32 +08:00
|
|
|
def self.generate_step_assets_element(step, _elements)
|
2020-10-14 18:08:04 +08:00
|
|
|
gen_element_content(step, step.assets, 'step_asset')
|
|
|
|
end
|
|
|
|
|
2020-10-14 18:12:32 +08:00
|
|
|
def self.generate_step_tables_element(step, _elements)
|
2020-10-14 18:08:04 +08:00
|
|
|
gen_element_content(step, step.tables, 'step_table')
|
2020-10-12 21:55:06 +08:00
|
|
|
end
|
|
|
|
|
2020-10-14 18:12:32 +08:00
|
|
|
def self.generate_step_checklists_element(step, _elements)
|
2020-10-14 18:08:04 +08:00
|
|
|
gen_element_content(step, step.checklists, 'step_checklist')
|
|
|
|
end
|
|
|
|
|
2020-10-14 18:12:32 +08:00
|
|
|
def self.generate_step_comments_element(step, _elements)
|
2020-10-14 18:08:04 +08:00
|
|
|
gen_element_content(step, nil, 'step_comments', true, 'asc')
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.generate_my_module_results_element(my_module, elements)
|
|
|
|
results = []
|
2020-10-12 21:55:06 +08:00
|
|
|
my_module.results.each do |result|
|
2020-10-14 18:08:04 +08:00
|
|
|
result_contents = []
|
|
|
|
elements.each do |report_element, children|
|
|
|
|
result_contents += public_send("generate_#{report_element}_element", result, children)
|
|
|
|
end
|
2020-10-12 21:55:06 +08:00
|
|
|
result_type = if result.asset
|
|
|
|
'result_asset'
|
|
|
|
elsif result.table
|
|
|
|
'result_table'
|
|
|
|
elsif result.result_text
|
|
|
|
'result_text'
|
|
|
|
end
|
2020-10-14 18:08:04 +08:00
|
|
|
results += gen_element_content(result, nil, result_type, true, nil, result_contents)
|
2020-10-12 21:55:06 +08:00
|
|
|
end
|
2020-10-14 18:08:04 +08:00
|
|
|
results
|
|
|
|
end
|
|
|
|
|
2020-10-14 18:12:32 +08:00
|
|
|
def self.generate_result_comments_element(result, _elements)
|
2020-10-14 18:08:04 +08:00
|
|
|
gen_element_content(result, nil, 'result_comments', true, 'asc')
|
2020-10-12 21:55:06 +08:00
|
|
|
end
|
|
|
|
|
2020-10-14 18:12:32 +08:00
|
|
|
def self.generate_my_module_activities_element(my_module, _elements)
|
2020-10-12 21:55:06 +08:00
|
|
|
gen_element_content(my_module, nil, 'my_module_activity', true, 'asc')
|
|
|
|
end
|
|
|
|
|
2020-10-14 18:12:32 +08:00
|
|
|
def self.generate_my_module_repositories_element(my_module, _elements)
|
2020-10-14 18:08:04 +08:00
|
|
|
repositories = my_module.experiment.project.assigned_repositories_and_snapshots
|
2020-10-12 21:55:06 +08:00
|
|
|
gen_element_content(my_module, repositories, 'my_module_repository', true, 'asc')
|
|
|
|
end
|
|
|
|
|
2016-02-12 23:52:43 +08:00
|
|
|
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
|
2017-03-09 23:02:52 +08:00
|
|
|
el.type_of = json_element['type_of']
|
|
|
|
el.sort_order = json_element['sort_order']
|
2017-06-05 18:24:06 +08:00
|
|
|
el.set_element_references(json_element['id'])
|
2016-02-12 23:52:43 +08:00
|
|
|
el.save!
|
2017-03-09 23:02:52 +08:00
|
|
|
|
|
|
|
if json_element['children'].present?
|
|
|
|
json_element['children'].each_with_index do |child, i|
|
2016-02-12 23:52:43 +08:00
|
|
|
save_json_element(child, i, el)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|