Update the search to abide the permissions [SCI-6151]

This commit is contained in:
Oleksii Kriuchykhin 2021-10-22 11:43:20 +02:00
parent c63090da8c
commit 2051ea5360
15 changed files with 120 additions and 292 deletions

View file

@ -36,27 +36,19 @@ class Checklist < ApplicationRecord
page = 1, page = 1,
_current_team = nil, _current_team = nil,
options = {}) options = {})
step_ids = step_ids = Step.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
Step
.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
.pluck(:id) .pluck(:id)
new_query = new_query = Checklist.distinct
Checklist .where(checklists: { step_id: step_ids })
.distinct .joins('LEFT JOIN checklist_items ON checklists.id = checklist_items.checklist_id')
.where('checklists.step_id IN (?)', step_ids) .where_attributes_like(['checklists.name', 'checklist_items.text'], query, options)
.joins('LEFT JOIN checklist_items ON ' \
'checklists.id = checklist_items.checklist_id')
.where_attributes_like(['checklists.name', 'checklist_items.text'],
query, options)
# Show all results if needed # Show all results if needed
if page == Constants::SEARCH_NO_LIMIT if page == Constants::SEARCH_NO_LIMIT
new_query new_query
else else
new_query new_query.limit(Constants::SEARCH_LIMIT).offset((page - 1) * Constants::SEARCH_LIMIT)
.limit(Constants::SEARCH_LIMIT)
.offset((page - 1) * Constants::SEARCH_LIMIT)
end end
end end
end end

View file

@ -18,25 +18,16 @@ class Comment < ApplicationRecord
_current_team = nil, _current_team = nil,
options = {} options = {}
) )
project_ids = project_ids = Project.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
Project
.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
.pluck(:id) .pluck(:id)
my_module_ids = my_module_ids = MyModule.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
MyModule
.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
.pluck(:id) .pluck(:id)
step_ids = step_ids = Step.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
Step
.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
.pluck(:id) .pluck(:id)
result_ids = result_ids = Result.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
Result
.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
.pluck(:id) .pluck(:id)
new_query = new_query = Comment.distinct
Comment.distinct
.joins(:user) .joins(:user)
.where( .where(
'(comments.associated_id IN (?) AND comments.type = ?) OR ' \ '(comments.associated_id IN (?) AND comments.type = ?) OR ' \
@ -48,16 +39,13 @@ class Comment < ApplicationRecord
step_ids, 'StepComment', step_ids, 'StepComment',
result_ids, 'ResultComment' result_ids, 'ResultComment'
) )
.where_attributes_like(['message', 'users.full_name'], .where_attributes_like(['message', 'users.full_name'], query, options)
query, options)
# Show all results if needed # Show all results if needed
if page == Constants::SEARCH_NO_LIMIT if page == Constants::SEARCH_NO_LIMIT
new_query new_query
else else
new_query new_query.limit(Constants::SEARCH_LIMIT).offset((page - 1) * Constants::SEARCH_LIMIT)
.limit(Constants::SEARCH_LIMIT)
.offset((page - 1) * Constants::SEARCH_LIMIT)
end end
end end

View file

@ -3,6 +3,16 @@
module PermissionCheckableModel module PermissionCheckableModel
extend ActiveSupport::Concern extend ActiveSupport::Concern
included do
include PermissionExtends
scope :with_granted_permissions, lambda { |user, permissions|
left_outer_joins(user_assignments: :user_role)
.where(user_assignments: { user: user })
.where('user_roles.permissions @> ARRAY[?]::varchar[]', permissions)
}
end
def permission_granted?(user, permission) def permission_granted?(user, permission)
user_role_permissions = load_user_role_permissions(user) user_role_permissions = load_user_role_permissions(user)
return false if user_role_permissions.blank? return false if user_role_permissions.blank?
@ -13,13 +23,10 @@ module PermissionCheckableModel
private private
def load_user_role_permissions(user) def load_user_role_permissions(user)
user_role_permissions =
if user_assignments.loaded? if user_assignments.loaded?
user_assignments.detect { |user_assignment| user_assignment.user == user }&.user_role&.permissions user_assignments.detect { |user_assignment| user_assignment.user == user }&.user_role&.permissions
else else
user_assignments.find_by(user: user)&.user_role&.permissions user_assignments.find_by(user: user)&.user_role&.permissions
end end
user_role_permissions
end end
end end

View file

@ -69,47 +69,25 @@ class Experiment < ApplicationRecord
current_team = nil, current_team = nil,
options = {} options = {}
) )
experiment_scope = experiment_search_scope( viewable_projects = Project.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT, current_team)
Project .pluck(:id)
.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT) new_query = Experiment.with_granted_permissions(user, ExperimentPermissions::READ)
.pluck(:id), .where(project: viewable_projects)
user
)
if current_team
new_query = experiment_search_scope(
Project.search(
user,
include_archived,
nil,
1,
current_team
).select('id'),
user
).where_attributes_like(SEARCHABLE_ATTRIBUTES, query, options)
return include_archived ? new_query : new_query.active
elsif include_archived
new_query = experiment_scope.where_attributes_like(SEARCHABLE_ATTRIBUTES, query, options)
else
new_query = experiment_scope.active
.where_attributes_like(SEARCHABLE_ATTRIBUTES, query, options) .where_attributes_like(SEARCHABLE_ATTRIBUTES, query, options)
end
new_query = new_query.active unless include_archived
# Show all results if needed # Show all results if needed
if page == Constants::SEARCH_NO_LIMIT if page == Constants::SEARCH_NO_LIMIT
new_query new_query
else else
new_query new_query.limit(Constants::SEARCH_LIMIT).offset((page - 1) * Constants::SEARCH_LIMIT)
.limit(Constants::SEARCH_LIMIT)
.offset((page - 1) * Constants::SEARCH_LIMIT)
end end
end end
def self.viewable_by_user(user, teams) def self.viewable_by_user(user, teams)
left_outer_joins(user_assignments: :user_role) with_granted_permissions(user, ExperimentPermissions::READ)
.where(project: Project.viewable_by_user(user, teams)) .where(project: Project.viewable_by_user(user, teams))
.where(user_assignments: { user: user })
.where('user_roles.permissions @> ARRAY[?]::varchar[]', %w[experiment_read])
end end
def archived_branch? def archived_branch?

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class MyModule < ApplicationRecord class MyModule < ApplicationRecord
SEARCHABLE_ATTRIBUTES = %i(name description).freeze SEARCHABLE_ATTRIBUTES = ['my_modules.name', 'my_modules.description']
include ArchivableModel include ArchivableModel
include SearchableModel include SearchableModel
@ -92,52 +92,26 @@ class MyModule < ApplicationRecord
current_team = nil, current_team = nil,
options = {} options = {}
) )
my_module_scope = my_module_search_scope( viewable_experiments = Experiment.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT, current_team)
Experiment .pluck(:id)
.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
.pluck(:id),
user
)
if current_team new_query = MyModule.with_granted_permissions(user, MyModulePermissions::READ)
new_query = my_module_search_scope( .where(experiment: viewable_experiments)
Experiment
.search(user,
include_archived,
nil,
1,
current_team)
.select('id'),
user
).where_attributes_like(SEARCHABLE_ATTRIBUTES, query, options)
if include_archived
return new_query
else
return new_query.where('my_modules.archived = ?', false)
end
elsif include_archived
new_query = my_module_scope.where_attributes_like(SEARCHABLE_ATTRIBUTES, query, options)
else
new_query = my_module_scope.where('my_modules.archived = ?', false)
.where_attributes_like(SEARCHABLE_ATTRIBUTES, query, options) .where_attributes_like(SEARCHABLE_ATTRIBUTES, query, options)
end
new_query = new_query.active unless include_archived
# Show all results if needed # Show all results if needed
if page == Constants::SEARCH_NO_LIMIT if page == Constants::SEARCH_NO_LIMIT
new_query new_query
else else
new_query new_query.limit(Constants::SEARCH_LIMIT).offset((page - 1) * Constants::SEARCH_LIMIT)
.limit(Constants::SEARCH_LIMIT)
.offset((page - 1) * Constants::SEARCH_LIMIT)
end end
end end
def self.viewable_by_user(user, teams) def self.viewable_by_user(user, teams)
left_outer_joins(user_assignments: :user_role) with_granted_permissions(user, MyModulePermissions::READ)
.where(experiment: Experiment.viewable_by_user(user, teams)) .where(experiment: Experiment.viewable_by_user(user, teams))
.where(user_assignments: { user: user })
.where('user_roles.permissions @> ARRAY[?]::varchar[]', %w[task_read])
end end
def navigable? def navigable?

View file

@ -81,64 +81,15 @@ class Project < ApplicationRecord
options = {} options = {}
) )
if current_team new_query = Project.viewable_by_user(user, current_team || user.teams)
new_query =
Project
.distinct
.joins(:user_assignments)
.where('projects.team_id = ?', current_team.id)
unless user.user_teams.find_by(team: current_team).try(:admin?)
# Admins see all projects in the team
new_query = new_query.where(
'projects.visibility = 1 OR user_assignments.user_id = ?',
user.id
)
end
new_query = new_query.where_attributes_like('projects.name', query, options)
if include_archived
return new_query
else
return new_query.where('projects.archived = ?', false)
end
else
new_query = Project
.distinct
.joins(team: :user_teams)
.where('user_teams.user_id = ?', user.id)
if include_archived
new_query =
new_query
.joins(:user_assignments)
.where(
'user_teams.role = 2 OR projects.visibility = 1 OR ' \
'user_assignments.user_id = ?',
user.id
)
.where_attributes_like('projects.name', query, options) .where_attributes_like('projects.name', query, options)
new_query = new_query.active unless include_archived
else
new_query =
new_query
.joins(:user_assignments)
.where(
'user_teams.role = 2 OR projects.visibility = 1 OR ' \
'user_assignments.user_id = ?',
user.id
)
.where_attributes_like('projects.name', query, options)
.where('projects.archived = ?', false)
end
end
# Show all results if needed # Show all results if needed
if page == Constants::SEARCH_NO_LIMIT if page == Constants::SEARCH_NO_LIMIT
new_query new_query
else else
new_query new_query.limit(Constants::SEARCH_LIMIT).offset((page - 1) * Constants::SEARCH_LIMIT)
.limit(Constants::SEARCH_LIMIT)
.offset((page - 1) * Constants::SEARCH_LIMIT)
end end
end end
@ -146,14 +97,11 @@ class Project < ApplicationRecord
# Admins see all projects in the team # Admins see all projects in the team
# Member of the projects can view # Member of the projects can view
# If project is visible everyone from the team can view it # If project is visible everyone from the team can view it
Project.where(team: teams) projects = Project.where(team: teams)
.left_outer_joins(team: :user_teams) .left_outer_joins(team: :user_teams)
.left_outer_joins(user_assignments: :user_role) .left_outer_joins(user_assignments: :user_role)
.where('projects.visibility = 1 OR '\ projects.where('projects.visibility = 1 OR (user_teams.user_id = ? AND user_teams.role = 2)', user)
'user_assignments.user_id = :user_id OR '\ .or(projects.with_granted_permissions(user, ProjectPermissions::READ))
'(user_teams.user_id = :user_id AND user_teams.role = 2)',
user_id: user.id)
.where('user_roles.permissions @> ARRAY[?]::varchar[]', %w[project_read])
.distinct .distinct
end end

View file

@ -123,14 +123,11 @@ class Protocol < ApplicationRecord
_current_team = nil, _current_team = nil,
options = {}) options = {})
team_ids = Team.joins(:user_teams) team_ids = Team.joins(:user_teams)
.where('user_teams.user_id = ?', user.id) .where(user_teams: { user_id: user.id })
.distinct .distinct
.pluck(:id) .pluck(:id)
module_ids = MyModule.search(user, module_ids = MyModule.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
include_archived,
nil,
Constants::SEARCH_NO_LIMIT)
.pluck(:id) .pluck(:id)
where_str = where_str =
@ -193,9 +190,7 @@ class Protocol < ApplicationRecord
if page == Constants::SEARCH_NO_LIMIT if page == Constants::SEARCH_NO_LIMIT
new_query new_query
else else
new_query new_query.limit(Constants::SEARCH_LIMIT).offset((page - 1) * Constants::SEARCH_LIMIT)
.limit(Constants::SEARCH_LIMIT)
.offset((page - 1) * Constants::SEARCH_LIMIT)
end end
end end

View file

@ -65,24 +65,18 @@ class Report < ApplicationRecord
options = {} options = {}
) )
project_ids = project_ids = Project.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
Project
.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
.pluck(:id) .pluck(:id)
new_query = new_query = Report.distinct
Report .where(reports: { project_id: project_ids })
.distinct
.where('reports.project_id IN (?)', project_ids)
.where_attributes_like(%i(name description), query, options) .where_attributes_like(%i(name description), query, options)
# Show all results if needed # Show all results if needed
if page == Constants::SEARCH_NO_LIMIT if page == Constants::SEARCH_NO_LIMIT
new_query new_query
else else
new_query new_query.limit(Constants::SEARCH_LIMIT).offset((page - 1) * Constants::SEARCH_LIMIT)
.limit(Constants::SEARCH_LIMIT)
.offset((page - 1) * Constants::SEARCH_LIMIT)
end end
end end

View file

@ -74,26 +74,16 @@ class Repository < RepositoryBase
repository = nil, repository = nil,
options = {} options = {}
) )
serchable_row_fields = [RepositoryRow::PREFIXED_ID_SQL, 'repository_rows.name', 'users.full_name']
repositories = repository&.id || Repository.accessible_by_teams(user.teams).pluck(:id) repositories = repository&.id || Repository.accessible_by_teams(user.teams).pluck(:id)
readable_rows = RepositoryRow.joins(:repository).where(repository_id: repositories) readable_rows = RepositoryRow.joins(:repository, :created_by).where(repository_id: repositories)
matched_by_user = readable_rows.joins(:created_by).where_attributes_like('users.full_name', query, options) repository_rows = readable_rows.where_attributes_like(serchable_row_fields, query, options)
prefixed_repository_row_ids = RepositoryRow.where(repository_id: repositories)
.where_attributes_like([RepositoryRow::PREFIXED_ID_SQL], query, options)
.select(:id)
repository_row_matches =
readable_rows.where_attributes_like(['repository_rows.name'], query, options).or(
readable_rows.where('repository_rows.id' => prefixed_repository_row_ids)
)
repository_rows = readable_rows.where(id: repository_row_matches)
repository_rows = repository_rows.or(readable_rows.where(id: matched_by_user))
Extends::REPOSITORY_EXTRA_SEARCH_ATTR.each do |_data_type, config| Extends::REPOSITORY_EXTRA_SEARCH_ATTR.each do |_data_type, config|
custom_cell_matches = repository_rows.joins(config[:includes]) custom_cell_matches = readable_rows.joins(config[:includes])
.where_attributes_like(config[:field], query, options) .where_attributes_like(config[:field], query, options)
repository_rows = repository_rows.or(readable_rows.where(id: custom_cell_matches)) repository_rows = repository_rows.or(readable_rows.where(id: custom_cell_matches))
end end
@ -103,8 +93,7 @@ class Repository < RepositoryBase
repository_rows.select('repositories.id AS id, COUNT(DISTINCT repository_rows.id) AS counter') repository_rows.select('repositories.id AS id, COUNT(DISTINCT repository_rows.id) AS counter')
.group('repositories.id') .group('repositories.id')
else else
repository_rows.limit(Constants::SEARCH_LIMIT) repository_rows.limit(Constants::SEARCH_LIMIT).offset((page - 1) * Constants::SEARCH_LIMIT)
.offset((page - 1) * Constants::SEARCH_LIMIT)
end end
end end

View file

@ -32,28 +32,22 @@ class Result < ApplicationRecord
page = 1, page = 1,
_current_team = nil, _current_team = nil,
options = {}) options = {})
module_ids = module_ids = MyModule.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT).pluck(:id)
MyModule
.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
.pluck(:id)
new_query = new_query =
Result Result
.distinct .distinct
.joins('LEFT JOIN result_texts ON results.id = result_texts.result_id') .joins('LEFT JOIN result_texts ON results.id = result_texts.result_id')
.where('results.my_module_id IN (?)', module_ids) .where(results: { my_module_id: module_ids })
.where_attributes_like(['results.name', 'result_texts.text'], .where_attributes_like(['results.name', 'result_texts.text'], query, options)
query, options)
new_query = new_query.where('results.archived = ?', false) unless include_archived new_query = new_query.active unless include_archived
# Show all results if needed # Show all results if needed
if page == Constants::SEARCH_NO_LIMIT if page == Constants::SEARCH_NO_LIMIT
new_query new_query
else else
new_query new_query.limit(Constants::SEARCH_LIMIT).offset((page - 1) * Constants::SEARCH_LIMIT)
.limit(Constants::SEARCH_LIMIT)
.offset((page - 1) * Constants::SEARCH_LIMIT)
end end
end end

View file

@ -51,23 +51,18 @@ class Step < ApplicationRecord
page = 1, page = 1,
_current_team = nil, _current_team = nil,
options = {}) options = {})
protocol_ids = protocol_ids = Protocol.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
Protocol
.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
.pluck(:id) .pluck(:id)
new_query = Step new_query = Step.distinct
.distinct .where(steps: { protocol_id: protocol_ids })
.where('steps.protocol_id IN (?)', protocol_ids) .where_attributes_like(%i(name description), query, options)
.where_attributes_like([:name, :description], query, options)
# Show all results if needed # Show all results if needed
if page == Constants::SEARCH_NO_LIMIT if page == Constants::SEARCH_NO_LIMIT
new_query new_query
else else
new_query new_query.limit(Constants::SEARCH_LIMIT).offset((page - 1) * Constants::SEARCH_LIMIT)
.limit(Constants::SEARCH_LIMIT)
.offset((page - 1) * Constants::SEARCH_LIMIT)
end end
end end

View file

@ -35,29 +35,21 @@ class Table < ApplicationRecord
page = 1, page = 1,
_current_team = nil, _current_team = nil,
options = {}) options = {})
step_ids = step_ids = Step.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
Step
.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
.joins(:step_tables) .joins(:step_tables)
.distinct .distinct
.pluck('step_tables.id') .pluck('step_tables.id')
result_ids = result_ids = Result.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
Result
.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
.joins(:result_table) .joins(:result_table)
.distinct .distinct
.pluck('result_tables.id') .pluck('result_tables.id')
table_query = table_query = Table.distinct
Table
.distinct
.joins('LEFT OUTER JOIN step_tables ON step_tables.table_id = tables.id') .joins('LEFT OUTER JOIN step_tables ON step_tables.table_id = tables.id')
.joins('LEFT OUTER JOIN result_tables ON ' \ .joins('LEFT OUTER JOIN result_tables ON result_tables.table_id = tables.id')
'result_tables.table_id = tables.id')
.joins('LEFT OUTER JOIN results ON result_tables.result_id = results.id') .joins('LEFT OUTER JOIN results ON result_tables.result_id = results.id')
.where('step_tables.id IN (?) OR result_tables.id IN (?)', .where('step_tables.id IN (?) OR result_tables.id IN (?)', step_ids, result_ids)
step_ids, result_ids)
if options[:whole_word].to_s == 'true' || if options[:whole_word].to_s == 'true' ||
options[:whole_phrase].to_s == 'true' options[:whole_phrase].to_s == 'true'
@ -111,9 +103,7 @@ class Table < ApplicationRecord
if page == Constants::SEARCH_NO_LIMIT if page == Constants::SEARCH_NO_LIMIT
new_query new_query
else else
new_query new_query.limit(Constants::SEARCH_LIMIT).offset((page - 1) * Constants::SEARCH_LIMIT)
.limit(Constants::SEARCH_LIMIT)
.offset((page - 1) * Constants::SEARCH_LIMIT)
end end
end end

View file

@ -24,23 +24,19 @@ class Tag < ApplicationRecord
page = 1, page = 1,
_current_team = nil, _current_team = nil,
options = {}) options = {})
project_ids = project_ids = Project.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
Project
.search(user, include_archived, nil, Constants::SEARCH_NO_LIMIT)
.pluck(:id) .pluck(:id)
new_query = Tag new_query = Tag
.distinct .distinct
.where('tags.project_id IN (?)', project_ids) .where(tags: { project_id: project_ids })
.where_attributes_like(:name, query, options) .where_attributes_like(:name, query, options)
# Show all results if needed # Show all results if needed
if page == Constants::SEARCH_NO_LIMIT if page == Constants::SEARCH_NO_LIMIT
new_query new_query
else else
new_query new_query.limit(Constants::SEARCH_LIMIT).offset((page - 1) * Constants::SEARCH_LIMIT)
.limit(Constants::SEARCH_LIMIT)
.offset((page - 1) * Constants::SEARCH_LIMIT)
end end
end end
end end

View file

@ -369,24 +369,14 @@ class User < ApplicationRecord
team_to_ignore = nil team_to_ignore = nil
) )
result = User.all result = User.all
result = result.where.not(confirmed_at: nil) if active_only
if active_only
result = result.where.not(confirmed_at: nil)
end
if team_to_ignore.present? if team_to_ignore.present?
ignored_ids = ignored_ids = UserTeam.select(:user_id).where(team_id: team_to_ignore.id)
UserTeam result = result.where.not('users.id IN (?)', ignored_ids)
.select(:user_id)
.where(team_id: team_to_ignore.id)
result =
result
.where("users.id NOT IN (?)", ignored_ids)
end end
result result.where_attributes_like(%i(full_name email), query).distinct
.where_attributes_like([:full_name, :email], query)
.distinct
end end
# Whether user is active (= confirmed) or not # Whether user is active (= confirmed) or not

View file

@ -22,12 +22,10 @@ module PermissionExtends
%w( %w(
READ READ
READ_ARCHIVED READ_ARCHIVED
ACTIVITIES_READ
MANAGE MANAGE
TASKS_MANAGE TASKS_MANAGE
USERS_READ USERS_READ
USERS_MANAGE USERS_MANAGE
READ_ARCHIVED
READ_CANVAS READ_CANVAS
ACTIVITIES_READ ACTIVITIES_READ
).each { |permission| const_set(permission, "experiment_#{permission.underscore}") } ).each { |permission| const_set(permission, "experiment_#{permission.underscore}") }