From 7f18fe12c11b7e637756bb3a717563aabe1e81f2 Mon Sep 17 00:00:00 2001 From: Matchu Date: Tue, 22 Jan 2013 23:52:34 -0600 Subject: [PATCH] user:owns, user:wants queries --- app/flex/flex_search.yml | 33 +++++++++++++++++------ app/models/closet_hanger.rb | 13 +++++++++ app/models/item/search/query.rb | 47 +++++++++++++++++++++++++++++---- config/initializers/flex.rb | 2 +- config/locales/en.yml | 9 +++++++ 5 files changed, 90 insertions(+), 14 deletions(-) diff --git a/app/flex/flex_search.yml b/app/flex/flex_search.yml index a3b3522c..15168564 100644 --- a/app/flex/flex_search.yml +++ b/app/flex/flex_search.yml @@ -5,6 +5,11 @@ # ANCHORS litheral key: it will not be used as template # you can store here fragments of queries to reuse in the templates below ANCHORS: + - &name_partial + multi_match: + query: <> + fields: <> + type: phrase - &species_support_id_partial term: species_support_id: <> @@ -14,18 +19,22 @@ ANCHORS: - &restricted_zone_id_partial terms: restricted_zone_id: <> + - &user_closet_hangers_ownership_partial + has_child: + type: closet_hanger + query: + bool: + must: + - term: + user_id: <> + - term: + owned: <> _names: - multi_match: - query: <> - fields: <> - type: phrase + *name_partial _negative_names: - multi_match: - query: <> - fields: <> - type: phrase + *name_partial _species_support_ids: *species_support_id_partial @@ -45,6 +54,12 @@ _restricted_zone_ids: _negative_restricted_zone_ids: *restricted_zone_id_partial +_user_closet_hanger_ownerships: + *user_closet_hangers_ownership_partial + +_negative_user_closet_hanger_ownerships: + *user_closet_hangers_ownership_partial + item_search: - query: bool: @@ -57,10 +72,12 @@ item_search: - <<_species_support_ids= ~>> - <<_occupied_zone_ids= ~>> - <<_restricted_zone_ids= ~>> + - <<_user_closet_hanger_ownerships= ~>> must_not: - <<_negative_names= ~>> - <<_negative_species_support_ids= ~>> - <<_negative_occupied_zone_ids= ~>> - <<_negative_restricted_zone_ids= ~>> + - <<_negative_user_closet_hanger_ownerships= ~>> sort: - name.<>.untouched diff --git a/app/models/closet_hanger.rb b/app/models/closet_hanger.rb index 99fe30f8..2de08f20 100644 --- a/app/models/closet_hanger.rb +++ b/app/models/closet_hanger.rb @@ -1,4 +1,6 @@ class ClosetHanger < ActiveRecord::Base + include Flex::Model + belongs_to :item belongs_to :list, :class_name => 'ClosetList' belongs_to :user @@ -29,6 +31,17 @@ class ClosetHanger < ActiveRecord::Base end before_validation :merge_quantities, :set_owned_by_list + + flex.parent :item, 'item' => 'closet_hanger' + flex.sync self + + def flex_source + { + :user_id => user_id, + :item_id => item_id, + :owned => owned? + }.to_json + end def verb(subject=:someone) self.class.verb(subject, owned?) diff --git a/app/models/item/search/query.rb b/app/models/item/search/query.rb index 37a73569..b9ac8621 100644 --- a/app/models/item/search/query.rb +++ b/app/models/item/search/query.rb @@ -7,11 +7,13 @@ class Item :species_support_id => Fields::SetField, :occupied_zone_id => Fields::SetField, :restricted_zone_id => Fields::SetField, - :name => Fields::SetField + :name => Fields::SetField, + :user_closet_hanger_ownership => Fields::SetField } def initialize(filters, user) @filters = filters + @user = user end def fields @@ -35,7 +37,8 @@ class Item final_flex_params = { :page => (options[:page] || 1), - :size => (options[:per_page] || 30) + :size => (options[:per_page] || 30), + :type => 'item' }.merge(flex_params) locales = I18n.fallbacks[I18n.locale] & @@ -64,6 +67,19 @@ class Item end end + # Okay, yeah, looks like this really does deserve a refactor, like + # _names and _negative_names do. (Or Flex could just make all variables + # accessible from partials... hint, hint) + [:_user_closet_hanger_ownerships, :_negative_user_closet_hanger_ownerships].each do |key| + if final_flex_params[key] + Item::Search.error 'not_logged_in' unless @user + + final_flex_params[key].each do |entry| + entry[:user_id] = @user.id + end + end + end + result = FlexSearch.item_search(final_flex_params) result.scoped_loaded_collection( :scopes => {'Item' => Item.includes(:translations)} @@ -73,14 +89,22 @@ class Item # Load the text query labels from I18n, so that when we see, say, # the filter "species:acara", we know it means species_support_id. TEXT_KEYS_BY_LABEL = {} + OWNERSHIP_KEYWORDS = {} I18n.available_locales.each do |locale| TEXT_KEYS_BY_LABEL[locale] = {} + OWNERSHIP_KEYWORDS[locale] = {} FIELD_CLASSES.keys.each do |key| # A locale can specify multiple labels for a key by separating by # commas: "occupies,zone,type" labels = I18n.translate("items.search.labels.#{key}", :locale => locale).split(',') labels.each { |label| TEXT_KEYS_BY_LABEL[locale][label] = key } + + {:owns => true, :wants => false}.each do |key, value| + translated_key = I18n.translate("items.search.labels.user_#{key}", + :locale => locale) + OWNERSHIP_KEYWORDS[locale][translated_key] = value + end end end @@ -98,27 +122,40 @@ class Item Item::Search.error 'not_found.zone', :zone_name => name end zone_set.map(&:id) + }, + :ownership => lambda { |keyword| + OWNERSHIP_KEYWORDS[I18n.locale][keyword].tap do |value| + if value.nil? + Item::Search.error 'not_found.ownership', :keyword => keyword + end + end } } TEXT_QUERY_RESOURCE_TYPES_BY_KEY = { :species_support_id => :species, :occupied_zone_id => :zone, - :restricted_zone_id => :zone + :restricted_zone_id => :zone, + :user_closet_hanger_ownership => :ownership } TEXT_FILTER_EXPR = /([+-]?)(?:([a-z]+):)?(?:"([^"]+)"|(\S+))/ def self.from_text(text, user=nil) filters = [] + + is_keyword = I18n.translate('items.search.flag_keywords.is') text.scan(TEXT_FILTER_EXPR) do |sign, label, quoted_value, unquoted_value| label ||= 'name' raw_value = quoted_value || unquoted_value is_positive = (sign != '-') - if label == 'is' + if label == is_keyword # is-filters are weird. "-is:nc" is transposed to something more # like "-nc:", then it's translated into a negative "is_nc" - # flag. + # flag. Fun fact: "nc:foobar" and "-nc:foobar" also work. A bonus, + # I guess. There's probably a good way to refactor this to avoid + # the unintended bonus syntax, but this is a darn good cheap + # technique for the time being. label = raw_value raw_value = nil end diff --git a/config/initializers/flex.rb b/config/initializers/flex.rb index d9f80ee0..993b9a0a 100644 --- a/config/initializers/flex.rb +++ b/config/initializers/flex.rb @@ -3,7 +3,7 @@ Flex::Configuration.configure do |config| # you MUST add your indexed model names here - config.flex_models = %w[ Item ] + config.flex_models = %w[ Item ClosetHanger ] # Add the your result extenders here config.result_extenders |= [ FlexSearchExtender ] diff --git a/config/locales/en.yml b/config/locales/en.yml index 4024ee7e..c1b97352 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -333,6 +333,12 @@ en: species: Species "%{species_name}" does not exist. Is it spelled correctly? zone: Zone "%{zone_name}" does not exist. Is it spelled correctly? + ownership: + I don't know what user:%{keyword} means. Is it spelled correctly? + not_logged_in: + The "user" filters are only available if you're logged in. + flag_keywords: + is: is labels: name: name is_nc: nc @@ -340,6 +346,9 @@ en: species_support_id: species occupied_zone_id: occupies,zone,type restricted_zone_id: restricts + user_closet_hanger_ownership: user + user_owns: owns + user_wants: wants neopets_pages: create: