diff --git a/plugins/elasticsearch/Gemfile b/plugins/elasticsearch/Gemfile new file mode 100644 index 0000000..8e147aa --- /dev/null +++ b/plugins/elasticsearch/Gemfile @@ -0,0 +1,2 @@ +gem 'elasticsearch-model' +gem 'elasticsearch-rails' diff --git a/plugins/elasticsearch/README.md b/plugins/elasticsearch/README.md new file mode 100644 index 0000000..245a38f --- /dev/null +++ b/plugins/elasticsearch/README.md @@ -0,0 +1,41 @@ +Elasticsearch Plugin +==================== + +Elasticsearch is as plugin to run searchs in noosfero through elasticsearch. + +The Version used is 1.7.5 due compatibility problems with gems and new versions. + +Download: https://www.elastic.co/downloads/past-releases/elasticsearch-1-7-5 + +INSTALL +======= + +Install dependencies + +Install elasticsearch package and start service. +By default, the service runs on port 9200 + +Install gems listed in plugin Gemfile. If this step fail, just copy the gems to core Gemfile +and run the command 'bundle install' + +Enable plugin +------------- + +Execute the command to enable Elasticsearch Plugin at your noosfero: + +./script/noosfero-plugins enable elasticsearch + +Active plugin +------------- + +As a Noosfero administrator user, go to administrator panel: + +- Click on "Enable/disable plugins" option +- Click on "Elasticsearch" check-box + +DEVELOPMENT +=========== + +To run tests for Elasticsearch: + +Use command 'rspec' diff --git a/plugins/elasticsearch/controllers/elasticsearch_plugin_controller.rb b/plugins/elasticsearch/controllers/elasticsearch_plugin_controller.rb new file mode 100644 index 0000000..270a899 --- /dev/null +++ b/plugins/elasticsearch/controllers/elasticsearch_plugin_controller.rb @@ -0,0 +1,64 @@ +class ElasticsearchPluginController < ApplicationController + no_design_blocks + + def search + @results = [] + @query = params[:q] + @checkbox = {} + terms = get_terms(params) + puts "=" * 80, terms, "=" * 80 + if params[:model].present? + params[:model].keys.each do |model| + @checkbox[model.to_sym] = true + klass = model.classify.constantize + query = get_query params[:q], klass + @results += klass.__elasticsearch__.search(query).records.to_a + end + end + + if params[:filter].present? + params[:filter].keys.each do |model| + params[:filter][model].keys.each do |filter| + @checkbox[filter.to_sym] = true + end + end + end + end + + private + + def get_query text, klass + query = {} + unless text.blank? + + fields = klass::SEARCHABLE_FIELDS.map {|k, v| "#{k}^#{v[:weight]}"} + + query = { + query: { + multi_match: { + query: text, + fields: fields, + operator: "and" + } + }, + filter: { + term: {visible: "true"} + } + } + end + query + end + + def get_terms params + terms = {} + return terms unless params[:filter].present? + params[:filter].keys.each do |model| + terms[model] = {} + params[:filter][model].keys.each do |filter| + @checkbox[filter.to_sym] = true + terms[model][params[:filter][model.to_sym][filter]] = filter + end + end + terms + end +end diff --git a/plugins/elasticsearch/lib/elasticsearch_plugin.rb b/plugins/elasticsearch/lib/elasticsearch_plugin.rb new file mode 100644 index 0000000..ffb0c4d --- /dev/null +++ b/plugins/elasticsearch/lib/elasticsearch_plugin.rb @@ -0,0 +1,48 @@ +class ElasticsearchPlugin < Noosfero::Plugin + + def self.plugin_name + # FIXME + "ElasticsearchPlugin" + end + + def self.plugin_description + # FIXME + _("A plugin that does this and that.") + end + + Noosfero::Application.class_eval do + config.after_initialize do + + Rails.application.eager_load! #TODO: REMOVE THIS LINE + + models = ActiveRecord::Base.descendants.select do |model| + model.const_defined?("SEARCHABLE_FIELDS") + end + + models.each do |model| + model.class_eval do + include Elasticsearch::Model + include Elasticsearch::Model::Callbacks + + settings index: { number_of_shards: 1 } do + mappings dynamic: 'false' do + model::SEARCHABLE_FIELDS.each do |field, value| + indexes field + end + end + model.__elasticsearch__.client.indices.delete \ + index: model.index_name rescue nil + model.__elasticsearch__.client.indices.create \ + index: model.index_name, + body: { + settings: model.settings.to_hash, + mappings: model.mappings.to_hash + } + + model.import + end + end + end + end + end +end diff --git a/plugins/elasticsearch/po/elasticsearch.pot b/plugins/elasticsearch/po/elasticsearch.pot new file mode 100644 index 0000000..da73cf5 --- /dev/null +++ b/plugins/elasticsearch/po/elasticsearch.pot @@ -0,0 +1,22 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: 1.3~rc2-1-ga15645d\n" +"POT-Creation-Date: 2015-10-30 16:35-0300\n" +"PO-Revision-Date: 2015-08-06 17:21-0300\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: plugins/template/lib/template_plugin.rb:10 +msgid "A plugin that does this and that." +msgstr "" diff --git a/plugins/elasticsearch/test/unit/index_models_test.rb b/plugins/elasticsearch/test/unit/index_models_test.rb new file mode 100644 index 0000000..fb27f7e --- /dev/null +++ b/plugins/elasticsearch/test/unit/index_models_test.rb @@ -0,0 +1,21 @@ +require 'test_helper' + +class IndexModelsTest < ActiveSupport::TestCase + + should "check index models on elasticsearch" do + fields = [] + mappings = [] + + ActiveRecord::Base.descendants.each do |model| + if model.const_defined?("SEARCHABLE_FIELDS") + mappings << model.mappings.instance_values['mapping'].keys.sort + fields << model::SEARCHABLE_FIELDS.keys.sort + end + end + + mappings.count.times do |i| + assert_equal mappings[i], fields[i] + end + end + +end diff --git a/plugins/elasticsearch/views/elasticsearch_plugin/_article_display.html.erb b/plugins/elasticsearch/views/elasticsearch_plugin/_article_display.html.erb new file mode 100644 index 0000000..cd586ab --- /dev/null +++ b/plugins/elasticsearch/views/elasticsearch_plugin/_article_display.html.erb @@ -0,0 +1,2 @@ + +Article: <%= article.name %> diff --git a/plugins/elasticsearch/views/elasticsearch_plugin/_community_display.html.erb b/plugins/elasticsearch/views/elasticsearch_plugin/_community_display.html.erb new file mode 100644 index 0000000..f35c383 --- /dev/null +++ b/plugins/elasticsearch/views/elasticsearch_plugin/_community_display.html.erb @@ -0,0 +1 @@ +Community: <%= community.name %> diff --git a/plugins/elasticsearch/views/elasticsearch_plugin/_person_display.html.erb b/plugins/elasticsearch/views/elasticsearch_plugin/_person_display.html.erb new file mode 100644 index 0000000..cfa742d --- /dev/null +++ b/plugins/elasticsearch/views/elasticsearch_plugin/_person_display.html.erb @@ -0,0 +1,2 @@ + +Person: <%= person.name %> diff --git a/plugins/elasticsearch/views/elasticsearch_plugin/search.html.erb b/plugins/elasticsearch/views/elasticsearch_plugin/search.html.erb new file mode 100644 index 0000000..b8f2f96 --- /dev/null +++ b/plugins/elasticsearch/views/elasticsearch_plugin/search.html.erb @@ -0,0 +1,36 @@ +

Search

+ +<%= form_tag controller: "elasticsearch_plugin", action: "search" do %> + <%= label_tag(:q, _("Search")) %> + <%= text_field_tag(:q, @query) %> + + <%= submit_tag _("Send") %> + + <%= check_box_tag 'model[communities]', 1, @checkbox[:communities] %> + <%= label_tag('communities', _("communities")) %> + + <%= check_box_tag 'model[people]', 1, @checkbox[:people] %> + <%= label_tag('people', _("people")) %> + + <%= check_box_tag 'model[articles]', 1, @checkbox[:articles] %> + <%= label_tag('articles', _("articles")) %> + + <%= check_box_tag 'filter[articles][gallery]', :type, @checkbox[:gallery] %> + <%= label_tag('gallery', _("gallery")) %> +<% end %> + +<% for result in @results %> + <% if result.is_a? Article %> + <%= render partial: "article_display", :locals => {:article => result} %> +
+ <% end %> + + <% if result.is_a? Person %> + <%= render partial: "person_display", :locals => {:person => result} %> +
+ <% end %> + <% if result.is_a? Community %> + <%= render partial: "community_display", :locals => {:community => result} %> +
+ <% end %> +<% end %> diff --git a/spec/models/community_spec.rb b/spec/models/community_spec.rb new file mode 100644 index 0000000..da15e86 --- /dev/null +++ b/spec/models/community_spec.rb @@ -0,0 +1,38 @@ +require 'rails_helper' +require 'rake' +require 'elasticsearch/extensions/test/cluster/tasks' + +RSpec.configure do |config| + config.before :each, elasticsearch: true do + puts '='*10, 'before', '='*10 + Elasticsearch::Extensions::Test::Cluster.start() unless Elasticsearch::Extensions::Test::Cluster.running? + end + + config.after :suite do + puts '='*10, 'after', '='*10 + Elasticsearch::Extensions::Test::Cluster.stop() if Elasticsearch::Extensions::Test::Cluster.running? + end +end + +RSpec.describe Community, type: :model, elasticsearch: true do + before do + Environment.create!(:name => 'Noosfero', :contact_email => 'noosfero@localhost.localdomain', :is_default => true) + + @environment = Environment.default + @environment.enabled_plugins = ['ElasticsearchPlugin'] + @environment.save! + + @community = Community.new(name: "Debian") + @community.save! + + sleep 2 + end + + it "assert true" do + communities = Community.__elasticsearch__.search({}).records.to_a + + p communities + + expect(true).to be true + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb new file mode 100644 index 0000000..88ff2d0 --- /dev/null +++ b/spec/rails_helper.rb @@ -0,0 +1,52 @@ +# This file is copied to spec/ when you run 'rails generate rspec:install' +ENV['RAILS_ENV'] ||= 'test' +require File.expand_path('../../config/environment', __FILE__) +# Prevent database truncation if the environment is production +abort("The Rails environment is running in production mode!") if Rails.env.production? +require 'spec_helper' +require 'rspec/rails' +# Add additional requires below this line. Rails is not loaded until this point! + +# Requires supporting ruby files with custom matchers and macros, etc, in +# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are +# run as spec files by default. This means that files in spec/support that end +# in _spec.rb will both be required and run as specs, causing the specs to be +# run twice. It is recommended that you do not name files matching this glob to +# end with _spec.rb. You can configure this pattern with the --pattern +# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. +# +# The following line is provided for convenience purposes. It has the downside +# of increasing the boot-up time by auto-requiring all files in the support +# directory. Alternatively, in the individual `*_spec.rb` files, manually +# require only the support files necessary. +# +# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } + +# Checks for pending migrations before tests are run. +# If you are not using ActiveRecord, you can remove this line. +ActiveRecord::Migration.maintain_test_schema! + +RSpec.configure do |config| + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_path = "#{::Rails.root}/spec/fixtures" + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true + + # RSpec Rails can automatically mix in different behaviours to your tests + # based on their file location, for example enabling you to call `get` and + # `post` in specs under `spec/controllers`. + # + # You can disable this behaviour by removing the line below, and instead + # explicitly tag your specs with their type, e.g.: + # + # RSpec.describe UsersController, :type => :controller do + # # ... + # end + # + # The different available types are documented in the features, such as in + # https://relishapp.com/rspec/rspec-rails/docs + config.infer_spec_type_from_file_location! +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..913e28a --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,92 @@ +# This file was generated by the `rails generate rspec:install` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# The `.rspec` file also contains a few flags that are not defaults but that +# users commonly want. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # These two settings work together to allow you to limit a spec run + # to individual examples or groups you care about by tagging them with + # `:focus` metadata. When nothing is tagged with `:focus`, all examples + # get run. + config.filter_run :focus + config.run_all_when_everything_filtered = true + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching + config.disable_monkey_patching! + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = 'doc' + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end -- libgit2 0.21.2