mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-11-11 08:51:32 +08:00
Fix content of the Load from templates table [SCI-8049] (#5088)
This commit is contained in:
parent
bee0fa2de9
commit
078f4583ec
1 changed files with 65 additions and 80 deletions
|
|
@ -3,6 +3,8 @@ class LoadFromRepositoryProtocolsDatatable < CustomDatatable
|
||||||
include ActiveRecord::Sanitization::ClassMethods
|
include ActiveRecord::Sanitization::ClassMethods
|
||||||
include InputSanitizeHelper
|
include InputSanitizeHelper
|
||||||
|
|
||||||
|
PREFIXED_ID_SQL = "('#{Protocol::ID_PREFIX}' || COALESCE(\"protocols\".\"parent_id\", \"protocols\".\"id\"))".freeze
|
||||||
|
|
||||||
def initialize(view, team, user)
|
def initialize(view, team, user)
|
||||||
super(view)
|
super(view)
|
||||||
@team = team
|
@team = team
|
||||||
|
|
@ -12,8 +14,8 @@ class LoadFromRepositoryProtocolsDatatable < CustomDatatable
|
||||||
def sortable_columns
|
def sortable_columns
|
||||||
@sortable_columns ||= [
|
@sortable_columns ||= [
|
||||||
'Protocol.name',
|
'Protocol.name',
|
||||||
'nr_of_versions',
|
'Protocol.version_number',
|
||||||
'Protocol.id',
|
'adjusted_parent_id',
|
||||||
'protocol_keywords_str',
|
'protocol_keywords_str',
|
||||||
'full_username_str',
|
'full_username_str',
|
||||||
'Protocol.published_on'
|
'Protocol.published_on'
|
||||||
|
|
@ -23,20 +25,18 @@ class LoadFromRepositoryProtocolsDatatable < CustomDatatable
|
||||||
def searchable_columns
|
def searchable_columns
|
||||||
@searchable_columns ||= [
|
@searchable_columns ||= [
|
||||||
'Protocol.name',
|
'Protocol.name',
|
||||||
'Protocol.id',
|
"Protocol.#{PREFIXED_ID_SQL}",
|
||||||
'Protocol.published_on'
|
'Protocol.published_on',
|
||||||
|
'Protocol.version_number',
|
||||||
|
'ProtocolKeyword.name'
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
# This hack is needed to display a correct amount of
|
def as_json(_options = {})
|
||||||
# searched entries (needed for pagination).
|
|
||||||
# This is needed because of usage of GROUP operator in SQL.
|
|
||||||
# See https://github.com/antillas21/ajax-datatables-rails/issues/112
|
|
||||||
def as_json(options = {})
|
|
||||||
{
|
{
|
||||||
draw: dt_params[:draw].to_i,
|
draw: dt_params[:draw].to_i,
|
||||||
recordsTotal: get_raw_records.length,
|
recordsTotal: get_raw_records_base.distinct.count,
|
||||||
recordsFiltered: filter_records(get_raw_records).length,
|
recordsFiltered: records.present? ? records.first.filtered_count : 0,
|
||||||
data: data
|
data: data
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
@ -46,33 +46,55 @@ class LoadFromRepositoryProtocolsDatatable < CustomDatatable
|
||||||
# Returns json of current protocols (already paginated)
|
# Returns json of current protocols (already paginated)
|
||||||
def data
|
def data
|
||||||
records.map do |record|
|
records.map do |record|
|
||||||
|
parent = record.parent || record
|
||||||
{
|
{
|
||||||
'DT_RowId': record.id,
|
DT_RowId: parent.id,
|
||||||
'0': escape_input(record.name),
|
'0': escape_input(record.name),
|
||||||
'1': record.nr_of_versions,
|
'1': record.version_number,
|
||||||
'2': record.code,
|
'2': parent.code,
|
||||||
'3': keywords_html(record),
|
'3': keywords_html(record),
|
||||||
'4': escape_input(record.full_username_str),
|
'4': escape_input(record.published_by.full_name),
|
||||||
'5': I18n.l(record.published_on, format: :full)
|
'5': I18n.l(record.published_on, format: :full)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_raw_records_base
|
def new_search_condition(column, value)
|
||||||
records =
|
model, column = column.split('.', 2)
|
||||||
Protocol
|
model = model.constantize
|
||||||
.where(team: @team)
|
|
||||||
.where(protocols: { protocol_type: Protocol.protocol_types[:in_repository_published_original] })
|
|
||||||
.joins("LEFT OUTER JOIN protocols protocol_versions "\
|
|
||||||
"ON protocol_versions.protocol_type = #{Protocol.protocol_types[:in_repository_published_version]} "\
|
|
||||||
"AND protocol_versions.parent_id = protocols.id")
|
|
||||||
.joins('LEFT OUTER JOIN "protocol_protocol_keywords" '\
|
|
||||||
'ON "protocol_protocol_keywords"."protocol_id" = "protocols"."id"')
|
|
||||||
.joins('LEFT OUTER JOIN "protocol_keywords"'\
|
|
||||||
'ON "protocol_protocol_keywords"."protocol_keyword_id" = "protocol_keywords"."id"')
|
|
||||||
.joins('LEFT OUTER JOIN users ON users.id = protocols.published_by_id').active
|
|
||||||
|
|
||||||
records.group('"protocols"."id"')
|
casted_column = case column
|
||||||
|
when PREFIXED_ID_SQL
|
||||||
|
::Arel::Nodes::SqlLiteral.new(PREFIXED_ID_SQL)
|
||||||
|
when 'published_on'
|
||||||
|
::Arel::Nodes::NamedFunction.new(
|
||||||
|
'CAST', [Arel.sql("to_char( protocols.published_on, '#{formated_date}' ) AS VARCHAR")]
|
||||||
|
)
|
||||||
|
else
|
||||||
|
::Arel::Nodes::NamedFunction.new('CAST', [model.arel_table[column.to_sym].as(typecast)])
|
||||||
|
end
|
||||||
|
casted_column.matches("%#{ActiveRecord::Base.sanitize_sql_like(value)}%")
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_records
|
||||||
|
super.select('COUNT("protocols"."id") OVER() AS filtered_count')
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_raw_records_base
|
||||||
|
original_without_versions = @team.protocols
|
||||||
|
.left_outer_joins(:published_versions)
|
||||||
|
.where(protocol_type: Protocol.protocol_types[:in_repository_published_original])
|
||||||
|
.where(published_versions: { id: nil })
|
||||||
|
.select(:id)
|
||||||
|
|
||||||
|
published_versions = @team.protocols
|
||||||
|
.where(protocol_type: Protocol.protocol_types[:in_repository_published_version])
|
||||||
|
.order('parent_id, version_number DESC')
|
||||||
|
.select('DISTINCT ON (parent_id) id')
|
||||||
|
|
||||||
|
Protocol.where("protocols.id IN ((#{original_without_versions.to_sql}) UNION (#{published_versions.to_sql}))")
|
||||||
|
.active
|
||||||
|
.with_granted_permissions(@user, ProtocolPermissions::READ)
|
||||||
end
|
end
|
||||||
|
|
||||||
# OVERRIDE - query database for records (this will be
|
# OVERRIDE - query database for records (this will be
|
||||||
|
|
@ -80,10 +102,17 @@ class LoadFromRepositoryProtocolsDatatable < CustomDatatable
|
||||||
# will return json
|
# will return json
|
||||||
def get_raw_records
|
def get_raw_records
|
||||||
get_raw_records_base
|
get_raw_records_base
|
||||||
|
.preload(:parent, :protocol_keywords, user_assignments: %i(user user_role))
|
||||||
|
.joins('LEFT OUTER JOIN "protocol_protocol_keywords" ' \
|
||||||
|
'ON "protocol_protocol_keywords"."protocol_id" = "protocols"."id"')
|
||||||
|
.joins('LEFT OUTER JOIN "protocol_keywords" ' \
|
||||||
|
'ON "protocol_protocol_keywords"."protocol_keyword_id" = "protocol_keywords"."id"')
|
||||||
|
.joins('LEFT OUTER JOIN "users" ON "users"."id" = "protocols"."published_by_id"')
|
||||||
|
.group('"protocols"."id"')
|
||||||
.select(
|
.select(
|
||||||
'"protocols".*',
|
'"protocols".*',
|
||||||
'STRING_AGG("protocol_keywords"."name", \', \') AS "protocol_keywords_str"',
|
'COALESCE("protocols"."parent_id", "protocols"."id") AS adjusted_parent_id',
|
||||||
'COUNT("protocol_versions"."id") + 1 AS "nr_of_versions"',
|
'STRING_AGG(DISTINCT("protocol_keywords"."name"), \', \') AS "protocol_keywords_str"',
|
||||||
'MAX("users"."full_name") AS "full_username_str"'
|
'MAX("users"."full_name") AS "full_username_str"'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
@ -91,59 +120,15 @@ class LoadFromRepositoryProtocolsDatatable < CustomDatatable
|
||||||
# Various helper methods
|
# Various helper methods
|
||||||
|
|
||||||
def keywords_html(record)
|
def keywords_html(record)
|
||||||
if record.protocol_keywords_str.blank?
|
if record.protocol_keywords.blank?
|
||||||
"<i>#{I18n.t('protocols.no_keywords')}</i>"
|
"<i>#{I18n.t('protocols.no_keywords')}</i>"
|
||||||
else
|
else
|
||||||
kws = record.protocol_keywords_str.split(', ')
|
|
||||||
res = []
|
res = []
|
||||||
kws.sort_by(&:downcase).each do |kw|
|
record.protocol_keywords.sort_by { |kw| kw.name.downcase }.each do |kw|
|
||||||
res << "<a href='#' data-action='filter' data-param='#{kw}'>#{kw}</a>"
|
sanitized_kw = sanitize_input(kw.name)
|
||||||
|
res << "<a href='#' data-action='filter' data-param='#{sanitized_kw}'>#{sanitized_kw}</a>"
|
||||||
end
|
end
|
||||||
sanitize_input(res.join(', '))
|
res.join(', ')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def timestamp_column_html(record)
|
|
||||||
if @type == :public
|
|
||||||
I18n.l(record.published_on, format: :full)
|
|
||||||
else
|
|
||||||
I18n.l(record.created_at, format: :full)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# OVERRIDE - This is only called when filtering results;
|
|
||||||
# when using GROUP BY function, SQL cannot perform a WHERE
|
|
||||||
# clause on aggregated columns (protocol keywords & users' full_name), but
|
|
||||||
# since we want those 2 columns to be searchable/filterable, we do an "inner"
|
|
||||||
# query where we select only protocol IDs which are filtered by those 2 columns
|
|
||||||
# using HAVING keyword (which is the correct way to filter aggregated columns).
|
|
||||||
# Another OR is then appended to the WHERE clause, checking if protocol is inside
|
|
||||||
# this list of IDs.
|
|
||||||
def build_conditions_for(query)
|
|
||||||
# Inner query to retrieve list of protocol IDs where concatenated
|
|
||||||
# protocol keywords string, or user's full_name contains searched query
|
|
||||||
search_val = dt_params[:search][:value]
|
|
||||||
records_having = get_raw_records_base.having(
|
|
||||||
::Arel::Nodes::NamedFunction.new(
|
|
||||||
'CAST',
|
|
||||||
[::Arel::Nodes::SqlLiteral.new("string_agg(\"protocol_keywords\".\"name\", ' ') AS #{typecast}")]
|
|
||||||
).matches("%#{sanitize_sql_like(search_val)}%").to_sql +
|
|
||||||
' OR ' +
|
|
||||||
::Arel::Nodes::NamedFunction.new(
|
|
||||||
'CAST',
|
|
||||||
[::Arel::Nodes::SqlLiteral.new("max(\"users\".\"full_name\") AS #{typecast}")]
|
|
||||||
).matches("%#{sanitize_sql_like(search_val)}%").to_sql +
|
|
||||||
' OR ' +
|
|
||||||
::Arel::Nodes::NamedFunction.new(
|
|
||||||
'CAST',
|
|
||||||
[::Arel::Nodes::SqlLiteral.new("COUNT(\"protocol_versions\".\"id\") + 1 AS #{typecast}")]
|
|
||||||
).matches("%#{sanitize_sql_like(search_val)}%").to_sql
|
|
||||||
).select(:id)
|
|
||||||
|
|
||||||
# Call parent function
|
|
||||||
criteria = super(query)
|
|
||||||
|
|
||||||
# Aight, now append another or
|
|
||||||
criteria.or(Protocol.arel_table[:id].in(records_having.arel))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue