Commit 46f8dc81 authored by Florian Hübsch's avatar Florian Hübsch
Browse files

Restrict search on current user.

parent 0a064d63
......@@ -53,7 +53,7 @@ module Chemotion
Collection.belongs_to_or_shared_by(current_user.id).find(params[:collection_id]).samples.includes(:molecule)
else
# All collection
Sample.joins(:collections).where('collections.user_id = ?', current_user.id).references(:collections).includes(:molecule).uniq
Sample.for_user(current_user.id).includes(:molecule).uniq
end.order("created_at DESC")
paginate(scope)
......
......@@ -57,22 +57,21 @@ module Chemotion
def scope_by_search_by_method_arg_and_collection_id(search_by_method, arg, collection_id)
scope = case search_by_method
when 'sum_formula', 'iupac_name', 'sample_name'
Sample.search_by(search_by_method, arg)
Sample.for_user(current_user.id).search_by(search_by_method, arg)
when 'reaction_name'
Reaction.search_by(search_by_method, arg)
Reaction.for_user(current_user.id).search_by(search_by_method, arg)
when 'wellplate_name'
Wellplate.search_by(search_by_method, arg)
Wellplate.for_user(current_user.id).search_by(search_by_method, arg)
when 'screen_name'
Screen.search_by(search_by_method, arg)
Screen.for_user(current_user.id).search_by(search_by_method, arg)
when 'substring'
AllElementSearch.new(arg).search_by_substring
AllElementSearch.new(arg, current_user.id).search_by_substring
end
# TODO only elements of current user
unless params[:collection_id] == "all"
scope = scope.by_collection_id(params[:collection_id].to_i)
end
scope # joins(:collections).where('collections.user_id = ?', current_user.id).references(:collections)
scope
end
def elements_by_scope(scope)
......@@ -83,29 +82,29 @@ module Chemotion
case scope.first
when Sample
elements[:samples] = scope
elements[:reactions] = scope.flat_map(&:reactions).uniq
elements[:wellplates] = scope.flat_map(&:well).compact.flat_map(&:wellplate).uniq
elements[:screens] = elements[:wellplates].flat_map(&:screen).compact.uniq
elements[:reactions] = (Reaction.for_user(current_user.id).by_material_ids(scope.map(&:id)) + Reaction.for_user(current_user.id).by_reactant_ids(scope.map(&:id)) + Reaction.for_user(current_user.id).by_product_ids(scope.map(&:id))).uniq
elements[:wellplates] = Wellplate.for_user(current_user.id).by_sample_ids(scope.map(&:id)).uniq
elements[:screens] = Screen.for_user(current_user.id).by_wellplate_ids(elements[:wellplates].map(&:id))
when Reaction
elements[:reactions] = scope
elements[:samples] = scope.flat_map(&:samples).uniq
elements[:wellplates] = elements[:samples].flat_map(&:well).compact.flat_map(&:wellplate).uniq
elements[:screens] = elements[:wellplates].flat_map(&:screen).compact.uniq
elements[:samples] = (Sample.for_user(current_user.id).by_reaction_reactant_ids(scope.map(&:id)) + Sample.for_user(current_user.id).by_reaction_product_ids(scope.map(&:id)) + Sample.for_user(current_user.id).by_reaction_material_ids(scope.map(&:id))).uniq
elements[:wellplates] = Wellplate.for_user(current_user.id).by_sample_ids(elements[:samples].map(&:id)).uniq
elements[:screens] = Screen.for_user(current_user.id).by_wellplate_ids(elements[:wellplates].map(&:id))
when Wellplate
elements[:wellplates] = scope
elements[:screens] = scope.flat_map(&:screen).compact.uniq
elements[:samples] = scope.flat_map(&:samples).uniq
elements[:reactions] = elements[:samples].flat_map(&:reactions).uniq
elements[:screens] = Screen.for_user(current_user.id).by_wellplate_ids(elements[:wellplates].map(&:id)).uniq
elements[:samples] = Sample.for_user(current_user.id).by_wellplate_ids(elements[:wellplates].map(&:id)).uniq
elements[:reactions] = (Reaction.for_user(current_user.id).by_material_ids(elements[:samples].map(&:id)) + Reaction.for_user(current_user.id).by_reactant_ids(elements[:samples].map(&:id)) + Reaction.for_user(current_user.id).by_product_ids(elements[:samples].map(&:id))).uniq
when Screen
elements[:screens] = scope
elements[:wellplates] = scope.flat_map(&:wellplates).uniq
elements[:samples] = elements[:wellplates].flat_map(&:wells).compact.flat_map(&:sample).uniq
elements[:reactions] = elements[:samples].flat_map(&:reactions).uniq
elements[:wellplates] = Wellplate.for_user(current_user.id).by_screen_ids(scope.map(&:id)).uniq
elements[:samples] = Sample.for_user(current_user.id).by_wellplate_ids(elements[:wellplates].map(&:id)).uniq
elements[:reactions] = (Reaction.for_user(current_user.id).by_material_ids(elements[:samples].map(&:id)) + Reaction.for_user(current_user.id).by_reactant_ids(elements[:samples].map(&:id)) + Reaction.for_user(current_user.id).by_product_ids(elements[:samples].map(&:id))).uniq
when AllElementSearch::Results
elements[:samples] = scope.samples
elements[:reactions] = (scope.reactions + elements[:samples].flat_map(&:reactions)).uniq
elements[:wellplates] = (scope.wellplates + elements[:samples].flat_map(&:well).compact.flat_map(&:wellplate)).uniq
elements[:screens] = (scope.screens + elements[:wellplates].flat_map(&:screen).compact).uniq
elements[:reactions] = (scope.reactions + (Reaction.for_user(current_user.id).by_material_ids(elements[:samples].map(&:id)) + Reaction.for_user(current_user.id).by_reactant_ids(elements[:samples].map(&:id)) + Reaction.for_user(current_user.id).by_product_ids(elements[:samples].map(&:id)))).uniq
elements[:wellplates] = (scope.wellplates + Wellplate.for_user(current_user.id).by_sample_ids(elements[:samples].map(&:id))).uniq
elements[:screens] = (scope.screens + Screen.for_user(current_user.id).by_wellplate_ids(elements[:wellplates].map(&:id))).uniq
end
elements
......@@ -150,7 +149,7 @@ module Chemotion
samples = scope.by_collection_id(params[:collection_id].to_i)
end
serialization_by_elements(elements_by_scope(samples), params[:page])
serialization_by_elements_and_page(elements_by_scope(samples), params[:page])
end
end
......@@ -173,7 +172,7 @@ module Chemotion
reactions = scope.by_collection_id(params[:collection_id].to_i)
end
serialization_by_elements(elements_by_scope(reactions), params[:page])
serialization_by_elements_and_page(elements_by_scope(reactions), params[:page])
end
end
......@@ -196,7 +195,7 @@ module Chemotion
wellplates = scope.by_collection_id(params[:collection_id].to_i)
end
serialization_by_elements(elements_by_scope(wellplates), params[:page])
serialization_by_elements_and_page(elements_by_scope(wellplates), params[:page])
end
end
......@@ -219,7 +218,7 @@ module Chemotion
screens = scope.by_collection_id(params[:collection_id].to_i)
end
serialization_by_elements(elements_by_scope(screens), params[:page])
serialization_by_elements_and_page(elements_by_scope(screens), params[:page])
end
end
......
......@@ -9,42 +9,42 @@ module Chemotion
suggestions
end
def search_possibilities_by_type(type)
def search_possibilities_by_type_and_user_id(type, user_id)
case type
when 'sample'
{
sample_name: Sample.by_name(params[:query]).pluck(:name).uniq,
sum_formula: Molecule.by_formula(params[:query]).map(&:sum_formular).uniq,
iupac_name: Molecule.by_iupac_name(params[:query]).map(&:iupac_name).uniq
sample_name: Sample.for_user(user_id).by_name(params[:query]).pluck(:name).uniq,
sum_formula: Molecule.for_user(user_id).by_formula(params[:query]).map(&:sum_formular).uniq,
iupac_name: Molecule.for_user(user_id).by_iupac_name(params[:query]).map(&:iupac_name).uniq
}
when 'reaction'
{
reaction_name: Reaction.by_name(params[:query]).pluck(:name).uniq,
sample_name: Sample.with_reactions.by_name(params[:query]).pluck(:name).uniq,
iupac_name: Molecule.with_reactions.by_iupac_name(params[:query]).map(&:iupac_name).uniq
reaction_name: Reaction.for_user(user_id).by_name(params[:query]).pluck(:name).uniq,
sample_name: Sample.for_user(user_id).with_reactions.by_name(params[:query]).pluck(:name).uniq,
iupac_name: Molecule.for_user(user_id).with_reactions.by_iupac_name(params[:query]).map(&:iupac_name).uniq
}
when 'wellplate'
{
wellplate_name: Wellplate.by_name(params[:query]).pluck(:name).uniq,
sample_name: Sample.with_wellplates.by_name(params[:query]).pluck(:name).uniq,
iupac_name: Molecule.with_wellplates.by_iupac_name(params[:query]).map(&:iupac_name).uniq
wellplate_name: Wellplate.for_user(user_id).by_name(params[:query]).pluck(:name).uniq,
sample_name: Sample.for_user(user_id).with_wellplates.by_name(params[:query]).pluck(:name).uniq,
iupac_name: Molecule.for_user(user_id).with_wellplates.by_iupac_name(params[:query]).map(&:iupac_name).uniq
}
when 'screen'
{
screen_name: Screen.by_name(params[:query]).pluck(:name).uniq,
conditions: Screen.by_conditions(params[:query]).pluck(:conditions).uniq,
requirements: Screen.by_requirements(params[:query]).pluck(:requirements).uniq
screen_name: Screen.for_user(user_id).by_name(params[:query]).pluck(:name).uniq,
conditions: Screen.for_user(user_id).by_conditions(params[:query]).pluck(:conditions).uniq,
requirements: Screen.for_user(user_id).by_requirements(params[:query]).pluck(:requirements).uniq
}
else
{
sample_name: Sample.by_name(params[:query]).pluck(:name).uniq,
sum_formula: Molecule.by_formula(params[:query]).map(&:sum_formular).uniq,
iupac_name: Molecule.by_iupac_name(params[:query]).map(&:iupac_name).uniq,
reaction_name: Reaction.by_name(params[:query]).pluck(:name).uniq,
wellplate_name: Wellplate.by_name(params[:query]).pluck(:name).uniq,
screen_name: Screen.by_name(params[:query]).pluck(:name).uniq,
conditions: Screen.by_conditions(params[:query]).pluck(:conditions).uniq,
requirements: Screen.by_requirements(params[:query]).pluck(:requirements).uniq
sample_name: Sample.for_user(user_id).by_name(params[:query]).pluck(:name).uniq,
sum_formula: Molecule.for_user(user_id).by_formula(params[:query]).map(&:sum_formular).uniq,
iupac_name: Molecule.for_user(user_id).by_iupac_name(params[:query]).map(&:iupac_name).uniq,
reaction_name: Reaction.for_user(user_id).by_name(params[:query]).pluck(:name).uniq,
wellplate_name: Wellplate.for_user(user_id).by_name(params[:query]).pluck(:name).uniq,
screen_name: Screen.for_user(user_id).by_name(params[:query]).pluck(:name).uniq,
conditions: Screen.for_user(user_id).by_conditions(params[:query]).pluck(:conditions).uniq,
requirements: Screen.for_user(user_id).by_requirements(params[:query]).pluck(:requirements).uniq
}
end
end
......@@ -55,11 +55,12 @@ module Chemotion
namespace :all do
desc 'Return all suggestions for AutoCompleteInput'
params do
requires :user_id, type: Integer, desc: 'Current user id'
requires :query, type: String, desc: 'Search query'
end
route_param :query do
get do
search_possibilities = search_possibilities_by_type('all')
search_possibilities = search_possibilities_by_type_and_user_id('all', params[:user_id])
{suggestions: search_possibilities_to_suggestions(search_possibilities)}
end
end
......@@ -72,7 +73,7 @@ module Chemotion
end
route_param :query do
get do
search_possibilities = search_possibilities_by_type('sample')
search_possibilities = search_possibilities_by_type_and_user_id('sample', params[:user_id])
{suggestions: search_possibilities_to_suggestions(search_possibilities)}
end
end
......@@ -85,7 +86,7 @@ module Chemotion
end
route_param :query do
get do
search_possibilities = search_possibilities_by_type('reaction')
search_possibilities = search_possibilities_by_type_and_user_id('reaction', params[:user_id])
{suggestions: search_possibilities_to_suggestions(search_possibilities)}
end
end
......@@ -98,7 +99,7 @@ module Chemotion
end
route_param :query do
get do
search_possibilities = search_possibilities_by_type('wellplate')
search_possibilities = search_possibilities_by_type_and_user_id('wellplate', params[:user_id])
{suggestions: search_possibilities_to_suggestions(search_possibilities)}
end
end
......@@ -111,7 +112,7 @@ module Chemotion
end
route_param :query do
get do
search_possibilities = search_possibilities_by_type('screen')
search_possibilities = search_possibilities_by_type_and_user_id('screen', params[:user_id])
{suggestions: search_possibilities_to_suggestions(search_possibilities)}
end
end
......
import 'whatwg-fetch';
export default class SuggestionsFetcher {
static fetchSuggestions(endpoint, query) {
// TODO: scope on current collection?
let promise = fetch(endpoint + query + '.json', {
static fetchSuggestionsForCurrentUser(endpoint, query, userId) {
let promise = fetch(endpoint + query + '.json?user_id=' + userId, {
credentials: 'same-origin'
}).then(response => {
return response.json();
......
......@@ -9,6 +9,7 @@ import SuggestionStore from '../stores/SuggestionStore';
import ElementActions from '../actions/ElementActions';
import UIStore from '../stores/UIStore';
import UIActions from '../actions/UIActions';
import UserStore from '../stores/UserStore';
export default class Search extends React.Component {
constructor(props) {
......@@ -28,7 +29,8 @@ export default class Search extends React.Component {
}
search(query) {
let promise = SuggestionsFetcher.fetchSuggestions('/api/v1/suggestions/' + this.state.elementType + '/', query);
let userState = UserStore.getState();
let promise = SuggestionsFetcher.fetchSuggestionsForCurrentUser('/api/v1/suggestions/' + this.state.elementType + '/', query, userState.currentUser.id);
return promise;
}
......
......@@ -2,6 +2,7 @@ module Collectable
extend ActiveSupport::Concern
included do
scope :for_user, ->(user_id) { joins(:collections).where('collections.user_id = ?', user_id).references(:collections) }
scope :by_collection_id, ->(id) { joins(:collections).where('collections.id = ?', id) }
scope :search_by, ->(search_by_method, arg) { public_send("search_by_#{search_by_method}", arg) }
end
......
class Molecule < ActiveRecord::Base
include Collectable
has_many :samples
has_many :collections, through: :samples
validates_uniqueness_of :inchikey
......
......@@ -33,6 +33,9 @@ class Reaction < ActiveRecord::Base
# scopes for suggestions
scope :by_name, ->(query) { where('name ILIKE ?', "%#{query}%") }
scope :by_material_ids, ->(ids) { joins(:starting_materials).where('samples.id IN (?)', ids) }
scope :by_reactant_ids, ->(ids) { joins(:reactants).where('samples.id IN (?)', ids) }
scope :by_product_ids, ->(ids) { joins(:products).where('samples.id IN (?)', ids) }
has_many :collections_reactions
has_many :collections, through: :collections_reactions
......
......@@ -34,6 +34,10 @@ class Sample < ActiveRecord::Base
sample_ids = Wellplate.all.flat_map(&:samples).map(&:id)
where(id: sample_ids)
}
scope :by_wellplate_ids, ->(ids) { joins(:wellplates).where('wellplates.id in (?)', ids) }
scope :by_reaction_reactant_ids, ->(ids) { joins(:reactions_as_reactant).where('reactions.id in (?)', ids) }
scope :by_reaction_product_ids, ->(ids) { joins(:reactions_as_product).where('reactions.id in (?)', ids) }
scope :by_reaction_material_ids, ->(ids) { joins(:reactions_as_starting_material).where('reactions.id in (?)', ids) }
has_many :collections_samples
has_many :collections, through: :collections_samples
......@@ -49,6 +53,7 @@ class Sample < ActiveRecord::Base
belongs_to :molecule
has_one :well
has_many :wellplates, through: :well
composed_of :amount, mapping: %w(amount_value, amount_unit)
......
......@@ -15,6 +15,7 @@ class Screen < ActiveRecord::Base
scope :by_name, ->(query) { where('name ILIKE ?', "%#{query}%") }
scope :by_conditions, ->(query) { where('conditions ILIKE ?', "%#{query}%") }
scope :by_requirements, ->(query) { where('requirements ILIKE ?', "%#{query}%") }
scope :by_wellplate_ids, ->(ids) { joins(:wellplates).where('wellplates.id in (?)', ids) }
has_many :collections_screens
has_many :collections, through: :collections_screens
......
......@@ -23,6 +23,8 @@ class Wellplate < ActiveRecord::Base
using: {trigram: {threshold: 0.0001}}
scope :by_name, ->(query) { where('name ILIKE ?', "%#{query}%") }
scope :by_sample_ids, -> (ids) { joins(:samples).where('samples.id in (?)', ids) }
scope :by_screen_ids, -> (ids) { where('screen_id in (?)', ids) }
has_many :collections_wellplates
has_many :collections, through: :collections_wellplates
......
class AllElementSearch
def initialize(term)
def initialize(term, user_id)
@term = term
@user_id = user_id
end
def search_by_substring
Results.new(PgSearch.multisearch(@term))
Results.new(PgSearch.multisearch(@term), @user_id)
end
class Results
attr_reader :samples, :results
def initialize(results)
def initialize(results, user_id)
@results = results
@user_id = user_id
end
def first
Results.new(@results.first)
Results.new(@results.first, @user_id)
end
def empty?
......@@ -23,23 +25,29 @@ class AllElementSearch
end
def by_collection_id(id)
Results.new(@results.select{|r| r.searchable.collections.map(&:id).include?(id)})
Results.new(@results.select{|r| r.searchable.collections.map(&:id).include?(id)}, @user_id)
end
def samples
@results.select{|r| r.searchable_type == 'Sample'}.map(&:searchable)
filter_results_by_type('Sample')
end
def reactions
@results.select{|r| r.searchable_type == 'Reaction'}.map(&:searchable)
filter_results_by_type('Reaction')
end
def wellplates
@results.select{|r| r.searchable_type == 'Wellplate'}.map(&:searchable)
filter_results_by_type('Wellplate')
end
def screens
@results.select{|r| r.searchable_type == 'Screen'}.map(&:searchable)
filter_results_by_type('Screen')
end
private
def filter_results_by_type(type)
@results.select{|r| r.searchable_type == type && r.searchable.collections.pluck(:user_id).include?(@user_id)}.map(&:searchable)
end
end
end
......@@ -2,13 +2,20 @@ require 'rails_helper'
RSpec.describe AllElementSearch do
subject { described_class }
let!(:s1) { create(:sample, name: "testtest") }
let!(:s2) { create(:sample, name: "t3st-1") }
let(:user) { create(:user) }
let(:collection) { create(:collection) }
let(:s1) { create(:sample, name: "testtest") }
let(:s2) { create(:sample, name: "t3st-1") }
before do
CollectionsSample.create!(collection: collection, sample: s1)
CollectionsSample.create!(collection: collection, sample: s2)
end
describe 'search_by_substring' do
it 'searches all elements for given substring' do
expect(subject.new('st').search_by_substring.results.size).to eq 2
expect(subject.new('-1').search_by_substring.results.size).to eq 1
expect(subject.new('st', user.id).search_by_substring.results.size).to eq 2
expect(subject.new('-1', user.id).search_by_substring.results.size).to eq 1
end
end
end
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment