diff --git a/app/controllers/my_modules_controller.rb b/app/controllers/my_modules_controller.rb
index 50b71be62..ecee8d96e 100644
--- a/app/controllers/my_modules_controller.rb
+++ b/app/controllers/my_modules_controller.rb
@@ -12,9 +12,11 @@ class MyModulesController < ApplicationController
toggle_task_state samples_index archive
complete_my_module repository repository_index
assign_repository_records unassign_repository_records]
- before_action :load_vars_nested, only: %I[new create]
- before_action :load_repository, only: %I[assign_repository_records
- unassign_repository_records]
+ before_action :load_vars_nested, only: %i(new create)
+ before_action :load_repository, only: %i(assign_repository_records
+ unassign_repository_records
+ repository_index)
+ before_action :load_columns_mappings, only: :repository_index
before_action :check_manage_permissions,
only: %i(update destroy description due_date)
before_action :check_view_info_permissions, only: :show
@@ -366,20 +368,18 @@ class MyModulesController < ApplicationController
# AJAX actions
def repository_index
- @repository = Repository.find_by_id(params[:repository_id])
- if @repository.nil? || !can_read_team?(@repository.team)
- render_403
- else
- respond_to do |format|
- format.html
- format.json do
- render json: ::RepositoryDatatable.new(view_context,
- @repository,
- @my_module,
- current_user)
- end
- end
- end
+ @draw = params[:draw].to_i
+ per_page = params[:length] == '-1' ? 100 : params[:length].to_i
+ page = (params[:start].to_i / per_page) + 1
+ records = RepositoryDatatableService.new(@repository,
+ params,
+ @columns_mappings,
+ current_user,
+ @my_module)
+ @assigned_rows = records.assigned_rows
+ @repository_row_count = records.repository_rows.count
+ @repository_rows = records.repository_rows.page(page).per(per_page)
+ render 'repository_rows/index.json'
end
# Submit actions
@@ -598,7 +598,18 @@ class MyModulesController < ApplicationController
def load_repository
@repository = Repository.find_by_id(params[:repository_id])
- render_404 unless @repository && can_read_team?(@repository.team)
+ render_404 unless @repository
+ render_403 unless can_read_team?(@repository.team)
+ end
+
+ def load_columns_mappings
+ # Make mappings of custom columns, so we have same id for every column
+ i = 5
+ @columns_mappings = {}
+ @repository.repository_columns.order(:id).each do |column|
+ @columns_mappings[column.id] = i.to_s
+ i += 1
+ end
end
def check_manage_permissions
diff --git a/app/controllers/repository_rows_controller.rb b/app/controllers/repository_rows_controller.rb
index ddb8dbd37..3366acf13 100644
--- a/app/controllers/repository_rows_controller.rb
+++ b/app/controllers/repository_rows_controller.rb
@@ -17,7 +17,9 @@ class RepositoryRowsController < ApplicationController
page = (params[:start].to_i / per_page) + 1
records = RepositoryDatatableService.new(@repository,
params,
- @columns_mappings)
+ @columns_mappings,
+ current_user)
+ @assigned_rows = records.assigned_rows
@repository_row_count = records.repository_rows.count
@repository_rows = records.repository_rows.page(page).per(per_page)
end
diff --git a/app/helpers/repository_datatable_helper.rb b/app/helpers/repository_datatable_helper.rb
index c93bdf09d..7604e7123 100644
--- a/app/helpers/repository_datatable_helper.rb
+++ b/app/helpers/repository_datatable_helper.rb
@@ -1,11 +1,15 @@
module RepositoryDatatableHelper
include InputSanitizeHelper
- def prepare_row_columns(repository_rows, repository, columns_mappings, team)
+ def prepare_row_columns(repository_rows,
+ repository,
+ columns_mappings,
+ team,
+ assigned_rows)
parsed_records = []
repository_rows.each do |record|
row = {
'DT_RowId': record.id,
- '1': assigned_row(record),
+ '1': assigned_row(record, assigned_rows),
'2': escape_input(record.name),
'3': I18n.l(record.created_at, format: :full),
'4': escape_input(record.created_by.full_name),
@@ -21,7 +25,6 @@ module RepositoryDatatableHelper
}
# Add custom columns
- # byebug
record.repository_cells.each do |cell|
row[columns_mappings[cell.repository_column.id]] =
custom_auto_link(
@@ -36,11 +39,11 @@ module RepositoryDatatableHelper
parsed_records
end
- def assigned_row(record)
- # if @assigned_rows && @assigned_rows.include?(record)
- # " "
- # else
- " "
- # end
+ def assigned_row(record, assigned_rows)
+ if assigned_rows&.include?(record)
+ " "
+ else
+ " "
+ end
end
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index ed5775492..fce0a148d 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -12,8 +12,6 @@ class Repository < ApplicationRecord
inverse_of: :repository, dependent: :destroy
has_many :report_elements, inverse_of: :repository, dependent: :destroy
has_many :repository_list_items, inverse_of: :repository, dependent: :destroy
- has_many :repository_searchable_rows,
- class_name: '::Views::Datatables::SearchRepository'
auto_strip_attributes :name, nullify: false
validates :name,
diff --git a/app/models/repository_cell.rb b/app/models/repository_cell.rb
index 44ed0f77b..13f07f371 100644
--- a/app/models/repository_cell.rb
+++ b/app/models/repository_cell.rb
@@ -8,6 +8,10 @@ class RepositoryCell < ActiveRecord::Base
validates :repository_row,
uniqueness: { scope: :repository_column }
+ belongs_to :repository_text_value, optional: true, foreign_key: :value_id
+ belongs_to :repository_date_value, optional: true, foreign_key: :value_id
+ belongs_to :repository_list_value, optional: true, foreign_key: :value_id
+
private
def repository_column_data_type
diff --git a/app/models/views/datatables/search_repository.rb b/app/models/views/datatables/search_repository.rb
deleted file mode 100644
index 2ff6a6f84..000000000
--- a/app/models/views/datatables/search_repository.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-module Views
- module Datatables
- class SearchRepository < ApplicationRecord
- belongs_to :repository
- # def self.records(repository, search_value)
- # # binding.pry
- # # # where('repository_rows.repository_id', repository.id).to_a
- # # where(repository_id: repository.id)
- # # .where()
- # end
-
- private
-
- # this isn't strictly necessary, but it will prevent
- # rails from calling save, which would fail anyway.
- def readonly?
- true
- end
- end
- end
-end
diff --git a/app/services/repository_datatable_service.rb b/app/services/repository_datatable_service.rb
index 61fe08d12..5f77a049c 100644
--- a/app/services/repository_datatable_service.rb
+++ b/app/services/repository_datatable_service.rb
@@ -1,73 +1,179 @@
class RepositoryDatatableService
- attr_reader :repository_rows
+ attr_reader :repository_rows, :assigned_rows
- def initialize(repository, params, mappings)
+ def initialize(repository, params, mappings, user, my_module = nil)
@mappings = mappings
@repository = repository
- process_query(params)
+ @mappings = mappings
+ @user = user
+ @my_module = my_module
+ @params = params
+ process_query
end
private
- def process_query(params)
- contitions = build_conditions(params)
- if contitions[:search_value].present?
- @repository_rows = search(contitions[:search_value])
+ def process_query
+ contitions = build_conditions(@params)
+ order_obj = contitions[:order_by_column]
+ search_value = contitions[:search_value]
+ if search_value.present?
+ @repository_rows = sort_rows(order_obj, search(search_value))
else
- @repository_rows = fetch_records
+ @repository_rows = sort_rows(order_obj, fetch_records)
end
- # byebug
end
def fetch_records
- RepositoryRow.preload(:repository_columns,
- :created_by,
- repository_cells: :value)
- .joins(:created_by)
- .where(repository: @repository)
+ repository_rows = RepositoryRow.preload(:repository_columns,
+ :created_by,
+ repository_cells: :value)
+ .joins(:created_by)
+ .where(repository: @repository)
+ if @my_module
+ @assigned_rows = @my_module.repository_rows
+ .preload(
+ :repository_columns,
+ :created_by,
+ repository_cells: :value
+ )
+ .joins(:created_by)
+ .where(repository: @repository)
+ return @assigned_rows if @params[:assigned] == 'assigned'
+ else
+ @assigned_rows = repository_rows.joins(
+ 'INNER JOIN my_module_repository_rows ON
+ (repository_rows.id = my_module_repository_rows.repository_row_id)'
+ )
+ end
+ repository_rows
end
def search(value)
- # binding.pry
- filtered_rows = @repository.repository_searchable_rows.where(
- 'name ILIKE :value
- OR to_char(created_at, :time) ILIKE :value
- OR user_full_name ILIKE :value
- OR text_value ILIKE :value
- OR date_value ILIKE :value
- OR list_value ILIKE :value',
- value: "%#{value}%",
- time: "DD.MM.YYYY HH24:MI"
- ).pluck(:id)
- fetch_records.where(id: filtered_rows)
+ includes_json = {
+ repository_cells: [:repository_text_value,
+ repository_list_value: :repository_list_item ]
+ }
+ RepositoryRow .left_outer_joins(:created_by)
+ .left_outer_joins(includes_json)
+ .where(repository: @repository)
+ .where_attributes_like(
+ ['repository_rows.name',
+ 'users.full_name',
+ 'repository_text_values.data',
+ 'repository_list_items.data'],
+ value
+ )
end
def build_conditions(params)
search_value = params[:search][:value]
- order_by_column = { column: params[:order][:column].to_i,
- dir: params[:order][:dir] }
+ order = params[:order].values.first
+ order_by_column = { column: order[:column].to_i,
+ dir: order[:dir] }
{ search_value: search_value, order_by_column: order_by_column }
end
def sortable_columns
- sort_array = [
+ array = [
'assigned',
- 'RepositoryRow.name',
- 'RepositoryRow.created_at',
- 'User.full_name'
+ 'repository_rows.name',
+ 'repository_rows.created_at',
+ 'users.full_name'
]
-
- sort_array.push(*repository_columns_sort_by)
- @sortable_columns = sort_array
- end
-
- def repository_columns_sort_by
- array = []
@repository.repository_columns.count.times do
- array << 'RepositoryCell.value'
+ array << 'repository_cell.value'
end
array
end
+ def sort_rows(column_obj, records)
+ dir = %w[DESC ASC].find { |dir| dir == column_obj[:dir].upcase } || 'ASC'
+ column_index = column_obj[:column]
+ col_order = @repository.repository_table_states
+ .find_by_user_id(@user.id)
+ .state['ColReorder']
+ column_id = col_order[column_index].to_i
+
+ if sortable_columns[column_id - 1] == 'assigned'
+ return records if @my_module && @params[:assigned] == 'assigned'
+ if @my_module
+ # Depending on the sort, order nulls first or
+ # nulls last on repository_cells association
+ return records.joins(
+ "LEFT OUTER JOIN my_module_repository_rows ON
+ (repository_rows.id = my_module_repository_rows.repository_row_id
+ AND (my_module_repository_rows.my_module_id = #{@my_module.id} OR
+ my_module_repository_rows.id IS NULL))"
+ ).order(
+ "my_module_repository_rows.id NULLS #{sort_null_direction(dir)}"
+ )
+ else
+ return sort_assigned_records(records, dir)
+ end
+ elsif sortable_columns[column_id - 1] == 'repository_cell.value'
+ id = @mappings.key(column_id.to_s)
+ type = RepositoryColumn.find_by_id(id)
+ return records unless type
+ return select_type(type.data_type, records, id, dir)
+ else
+ return records.order("#{sortable_columns[column_id - 1]} #{dir}")
+ end
+ end
+
+ def sort_assigned_records(records, direction)
+ assigned = records.joins(:my_module_repository_rows).distinct.pluck(:id)
+ unassigned = records.where.not(id: assigned).pluck(:id)
+ if direction == 'ASC'
+ ids = assigned + unassigned
+ elsif direction == 'DESC'
+ ids = unassigned + assigned
+ end
+
+ order_by_index = ActiveRecord::Base.send(
+ :sanitize_sql_array,
+ ["position((',' || repository_rows.id || ',') in ?)",
+ ids.join(',') + ',']
+ )
+ records.order(order_by_index)
+ end
+
+ def select_type(type, records, id, dir)
+ return filter_by_text_value(
+ records, id, dir) if type == 'RepositoryTextValue'
+ return filter_by_list_value(
+ records, id, dir) if type == 'RepositoryListValue'
+ end
+
+ def sort_null_direction(val)
+ val == 'ASC' ? 'LAST' : 'FIRST'
+ end
+
+ def filter_by_text_value(records, id, dir)
+ return records.joins(
+ "LEFT OUTER JOIN (SELECT repository_cells.repository_row_id,
+ repository_text_values.data AS value
+ FROM repository_cells
+ INNER JOIN repository_text_values
+ ON repository_text_values.id = repository_cells.value_id
+ WHERE repository_cells.repository_column_id = #{id}) AS values
+ ON values.repository_row_id = repository_rows.id"
+ ).order("values.value #{dir}")
+ end
+
+ def filter_by_list_value(records, id, dir)
+ return records.joins(
+ "LEFT OUTER JOIN (SELECT repository_cells.repository_row_id,
+ repository_list_items.data AS value
+ FROM repository_cells
+ INNER JOIN repository_list_values
+ ON repository_list_values.id = repository_cells.value_id
+ INNER JOIN repository_list_items
+ ON repository_list_values.repository_list_item_id =
+ repository_list_items.id
+ WHERE repository_cells.repository_column_id = #{id}) AS values
+ ON values.repository_row_id = repository_rows.id"
+ ).order("values.value #{dir}")
+ end
end
diff --git a/app/views/repository_rows/index.json.jbuilder b/app/views/repository_rows/index.json.jbuilder
index 23af2e9f3..c747bd696 100644
--- a/app/views/repository_rows/index.json.jbuilder
+++ b/app/views/repository_rows/index.json.jbuilder
@@ -2,5 +2,9 @@ json.draw @draw
json.recordsTotal @repository_rows.total_count
json.recordsFiltered @repository_row_count
json.data do
- json.array! prepare_row_columns(@repository_rows, @repository, @columns_mappings, @repository.team)
+ json.array! prepare_row_columns(@repository_rows,
+ @repository,
+ @columns_mappings,
+ @repository.team,
+ @assigned_rows)
end
diff --git a/db/migrate/20180306074931_create_search_repositories.rb b/db/migrate/20180306074931_create_search_repositories.rb
deleted file mode 100644
index 9311752f9..000000000
--- a/db/migrate/20180306074931_create_search_repositories.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class CreateSearchRepositories < ActiveRecord::Migration[5.1]
- def change
- create_view :search_repositories
- end
-end
diff --git a/db/schema.rb b/db/schema.rb
index a3a437072..4fac94123 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.define(version: 20180306074931) do
+ActiveRecord::Schema.define(version: 20180207095200) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -964,65 +964,4 @@ ActiveRecord::Schema.define(version: 20180306074931) do
JOIN user_teams ON ((teams.id = user_teams.team_id)));
SQL
- create_view "search_repositories", sql_definition: <<-SQL
- SELECT DISTINCT repository_rows.id,
- repository_rows.repository_id,
- repository_rows.created_by_id,
- repository_rows.last_modified_by_id,
- repository_rows.name,
- repository_rows.created_at,
- repository_rows.updated_at,
- users.full_name AS user_full_name,
- "values".text_value,
- "values".date_value,
- "values".list_value
- FROM ((repository_rows
- JOIN ( SELECT users_1.id,
- users_1.full_name,
- users_1.initials,
- users_1.email,
- users_1.encrypted_password,
- users_1.reset_password_token,
- users_1.reset_password_sent_at,
- users_1.remember_created_at,
- users_1.sign_in_count,
- users_1.current_sign_in_at,
- users_1.last_sign_in_at,
- users_1.current_sign_in_ip,
- users_1.last_sign_in_ip,
- users_1.created_at,
- users_1.updated_at,
- users_1.avatar_file_name,
- users_1.avatar_content_type,
- users_1.avatar_file_size,
- users_1.avatar_updated_at,
- users_1.confirmation_token,
- users_1.confirmed_at,
- users_1.confirmation_sent_at,
- users_1.unconfirmed_email,
- users_1.invitation_token,
- users_1.invitation_created_at,
- users_1.invitation_sent_at,
- users_1.invitation_accepted_at,
- users_1.invitation_limit,
- users_1.invited_by_type,
- users_1.invited_by_id,
- users_1.invitations_count,
- users_1.tutorial_status,
- users_1.current_team_id,
- users_1.authentication_token,
- users_1.settings
- FROM users users_1) users ON ((users.id = repository_rows.created_by_id)))
- LEFT JOIN ( SELECT repository_cells.repository_row_id,
- repository_text_values.data AS text_value,
- to_char(repository_date_values.data, 'DD.MM.YYYY HH24:MI'::text) AS date_value,
- ( SELECT repository_list_items.data
- FROM repository_list_items
- WHERE (repository_list_items.id = repository_list_values.repository_list_item_id)) AS list_value
- FROM (((repository_cells
- JOIN repository_text_values ON ((repository_text_values.id = repository_cells.value_id)))
- FULL JOIN repository_date_values ON ((repository_date_values.id = repository_cells.value_id)))
- FULL JOIN repository_list_values ON ((repository_list_values.id = repository_cells.value_id)))) "values" ON (("values".repository_row_id = repository_rows.id)));
- SQL
-
end
diff --git a/db/views/search_repositories_v01.sql b/db/views/search_repositories_v01.sql
deleted file mode 100644
index e9112c506..000000000
--- a/db/views/search_repositories_v01.sql
+++ /dev/null
@@ -1,28 +0,0 @@
-SELECT DISTINCT
- repository_rows.*,
- users.full_name AS user_full_name,
- values.text_value AS text_value,
- values.date_value AS date_value,
- values.list_value AS list_value
- FROM repository_rows
- INNER JOIN (
- SELECT users.*
- FROM users
- ) AS users
- ON users.id = repository_rows.created_by_id
- LEFT OUTER JOIN (
- SELECT repository_cells.repository_row_id,
- repository_text_values.data AS text_value,
- to_char(repository_date_values.data, 'DD.MM.YYYY HH24:MI') AS date_value,
- ( SELECT repository_list_items.data
- FROM repository_list_items
- WHERE repository_list_items.id = repository_list_values.repository_list_item_id ) AS list_value
- FROM repository_cells
- INNER JOIN repository_text_values
- ON repository_text_values.id = repository_cells.value_id
- FULL OUTER JOIN repository_date_values
- ON repository_date_values.id = repository_cells.value_id
- FUll OUTER JOIN repository_list_values
- ON repository_list_values.id = repository_cells.value_id
- ) AS values
- ON values.repository_row_id = repository_rows.id