@ -3,7 +3,6 @@ dist: bionic
|
||||
cache: bundler
|
||||
services:
|
||||
- postgresql
|
||||
- elasticsearch
|
||||
addons:
|
||||
postgresql: "9.4"
|
||||
chrome: stable
|
||||
@ -19,7 +18,5 @@ before_script:
|
||||
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
||||
- chmod +x ./cc-test-reporter
|
||||
- ./cc-test-reporter before-build
|
||||
# allow elasticsearch to be ready - https://docs.travis-ci.com/user/database-setup/#ElasticSearch
|
||||
- sleep 10
|
||||
after_script:
|
||||
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
||||
|
||||
3
Gemfile
3
Gemfile
@ -16,10 +16,9 @@ gem 'unicorn'
|
||||
gem 'kaminari', '~> 1.1.1'
|
||||
gem "simple_form", ">= 3.0.0"
|
||||
gem 'rollbar', '2.8.3'
|
||||
gem 'pg_search', '2.1.4'
|
||||
gem 'prawn', '~> 2.2.0'
|
||||
gem 'prawn-table', '~> 0.2.2'
|
||||
gem 'elasticsearch-model'
|
||||
gem 'elasticsearch-rails'
|
||||
gem 'skylight'
|
||||
gem 'sidekiq', '5.1.3'
|
||||
gem 'sidekiq-cron', '~> 1.1.0'
|
||||
|
||||
44
Gemfile.lock
44
Gemfile.lock
@ -118,29 +118,14 @@ GEM
|
||||
dotenv-rails (2.7.1)
|
||||
dotenv (= 2.7.1)
|
||||
railties (>= 3.2, < 6.1)
|
||||
elasticsearch (1.0.8)
|
||||
elasticsearch-api (= 1.0.7)
|
||||
elasticsearch-transport (= 1.0.7)
|
||||
elasticsearch-api (1.0.7)
|
||||
multi_json
|
||||
elasticsearch-model (0.1.7)
|
||||
activesupport (> 3)
|
||||
elasticsearch (> 0.4)
|
||||
hashie
|
||||
elasticsearch-rails (0.1.7)
|
||||
elasticsearch-transport (1.0.7)
|
||||
faraday
|
||||
multi_json
|
||||
erubi (1.7.1)
|
||||
erubi (1.9.0)
|
||||
erubis (2.7.0)
|
||||
et-orbi (1.1.7)
|
||||
tzinfo
|
||||
execjs (2.7.0)
|
||||
fabrication (2.20.1)
|
||||
faker (1.9.3)
|
||||
faker (1.9.6)
|
||||
i18n (>= 0.7)
|
||||
faraday (0.9.1)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ffi (1.12.2)
|
||||
formtastic (3.1.5)
|
||||
actionpack (>= 3.2.13)
|
||||
@ -154,7 +139,6 @@ GEM
|
||||
has_scope (0.6.0)
|
||||
actionpack (>= 3.2, < 5)
|
||||
activesupport (>= 3.2, < 5)
|
||||
hashie (3.4.1)
|
||||
hstore_translate (1.0.0)
|
||||
activerecord (>= 3.1.0)
|
||||
http-cookie (1.0.3)
|
||||
@ -207,7 +191,6 @@ GEM
|
||||
mini_portile2 (2.4.0)
|
||||
minitest (5.14.0)
|
||||
multi_json (1.11.2)
|
||||
multipart-post (2.0.0)
|
||||
net-scp (2.0.0)
|
||||
net-ssh (>= 2.6.5, < 6.0.0)
|
||||
net-ssh (5.2.0)
|
||||
@ -220,8 +203,9 @@ GEM
|
||||
ast (~> 2.4.0)
|
||||
pdf-core (0.7.0)
|
||||
pg (0.21.0)
|
||||
polyamorous (1.3.3)
|
||||
activerecord (>= 3.0)
|
||||
pg_search (2.1.4)
|
||||
activerecord (>= 4.2)
|
||||
activesupport (>= 4.2)
|
||||
prawn (2.2.2)
|
||||
pdf-core (~> 0.7.0)
|
||||
ttfunk (~> 1.5)
|
||||
@ -266,12 +250,11 @@ GEM
|
||||
rainbow (3.0.0)
|
||||
raindrops (0.16.0)
|
||||
rake (13.0.1)
|
||||
ransack (1.8.6)
|
||||
actionpack (>= 3.0)
|
||||
activerecord (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
ransack (1.8.10)
|
||||
actionpack (>= 3.0, < 5.2)
|
||||
activerecord (>= 3.0, < 5.2)
|
||||
activesupport (>= 3.0, < 5.2)
|
||||
i18n
|
||||
polyamorous (~> 1.3.2)
|
||||
rb-fsevent (0.10.3)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
@ -290,13 +273,13 @@ GEM
|
||||
multi_json
|
||||
rspec-core (3.9.1)
|
||||
rspec-support (~> 3.9.1)
|
||||
rspec-expectations (3.9.0)
|
||||
rspec-expectations (3.9.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-mocks (3.9.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-rails (3.9.0)
|
||||
rspec-rails (3.9.1)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
@ -333,7 +316,7 @@ GEM
|
||||
selenium-webdriver (3.142.7)
|
||||
childprocess (>= 0.5, < 4.0)
|
||||
rubyzip (>= 1.2.2)
|
||||
shoulda-matchers (3.1.2)
|
||||
shoulda-matchers (3.1.3)
|
||||
activesupport (>= 4.0.0)
|
||||
sidekiq (5.1.3)
|
||||
concurrent-ruby (~> 1.0)
|
||||
@ -414,8 +397,6 @@ DEPENDENCIES
|
||||
database_cleaner (= 1.6.2)
|
||||
devise (~> 4.7.1)
|
||||
dotenv-rails (~> 2.7.1)
|
||||
elasticsearch-model
|
||||
elasticsearch-rails
|
||||
fabrication (~> 2.20)
|
||||
faker (~> 1.9)
|
||||
has_scope
|
||||
@ -426,6 +407,7 @@ DEPENDENCIES
|
||||
letter_opener (= 1.4.1)
|
||||
localeapp (= 2.1.1)
|
||||
pg (= 0.21.0)
|
||||
pg_search (= 2.1.4)
|
||||
prawn (~> 2.2.0)
|
||||
prawn-table (~> 0.2.2)
|
||||
pundit (~> 2.0.0)
|
||||
|
||||
@ -20,11 +20,6 @@ class MembersController < ApplicationController
|
||||
def toggle_active
|
||||
find_member
|
||||
@member.toggle(:active).save!
|
||||
if @member.active
|
||||
@member.add_all_posts_to_index
|
||||
else
|
||||
@member.remove_all_posts_from_index
|
||||
end
|
||||
respond_to do |format|
|
||||
format.json { head :ok }
|
||||
format.html { redirect_to :back }
|
||||
|
||||
@ -4,31 +4,22 @@ class PostsController < ApplicationController
|
||||
has_scope :by_organization, as: :org
|
||||
|
||||
def index
|
||||
if (query = params[:q]).present?
|
||||
# match query term on fields
|
||||
must = [ { multi_match: {
|
||||
query: query.to_s,
|
||||
type: "phrase_prefix",
|
||||
fields: ["title^2", "description", "tags^2"]
|
||||
} } ]
|
||||
if current_organization.present?
|
||||
# filter by organization
|
||||
must << { term: { organization_id: { value: current_organization.id } } }
|
||||
end
|
||||
posts = model.__elasticsearch__.search(
|
||||
query: {
|
||||
bool: {
|
||||
must: must
|
||||
}
|
||||
}
|
||||
).page(params[:page]).per(25).records
|
||||
else
|
||||
posts = model.active.of_active_members
|
||||
if current_organization.present?
|
||||
posts = posts.merge(current_organization.posts)
|
||||
end
|
||||
posts = apply_scopes(posts).page(params[:page]).per(25)
|
||||
context = model.active.of_active_members
|
||||
if current_organization.present?
|
||||
context = context.where(
|
||||
organization_id: current_organization.id
|
||||
)
|
||||
end
|
||||
|
||||
posts = if (query = params[:q]).present?
|
||||
context.
|
||||
search_by_query(query).
|
||||
page(params[:page]).
|
||||
per(25)
|
||||
else
|
||||
apply_scopes(context).page(params[:page]).per(25)
|
||||
end
|
||||
|
||||
instance_variable_set("@#{resources}", posts)
|
||||
end
|
||||
|
||||
|
||||
@ -44,18 +44,6 @@ class Member < ActiveRecord::Base
|
||||
member_uid
|
||||
end
|
||||
|
||||
def remove_all_posts_from_index
|
||||
Post.with_member.where("members.id = ?", self.id).find_each do |post|
|
||||
post.delete_document
|
||||
end
|
||||
end
|
||||
|
||||
def add_all_posts_to_index
|
||||
Post.with_member.where("members.id = ?", self.id).find_each do |post|
|
||||
post.update_or_delete_document(self)
|
||||
end
|
||||
end
|
||||
|
||||
def assign_registration_number
|
||||
self.member_uid ||= organization.next_reg_number_seq
|
||||
end
|
||||
|
||||
@ -1,40 +1,16 @@
|
||||
require 'elasticsearch/model'
|
||||
|
||||
class Post < ActiveRecord::Base
|
||||
include Taggable
|
||||
include PgSearch
|
||||
|
||||
# Elasticsearch::Model doesn't work well with STI, so
|
||||
# include it in subclasses directly.
|
||||
def self.inherited(child)
|
||||
super
|
||||
|
||||
child.instance_eval do
|
||||
include Elasticsearch::Model
|
||||
|
||||
after_commit :index_document, on: :create
|
||||
after_commit :update_or_delete_document, on: :update
|
||||
after_commit :delete_document, on: :destroy
|
||||
|
||||
settings(
|
||||
analysis: {
|
||||
analyzer: {
|
||||
normal: {
|
||||
tokenizer: "standard",
|
||||
# lowercase, unaccent
|
||||
filter: %w[lowercase asciifolding]
|
||||
}
|
||||
}
|
||||
}
|
||||
) do
|
||||
mapping do
|
||||
indexes :title, analyzer: "normal"
|
||||
indexes :description, analyzer: "normal"
|
||||
indexes :tags
|
||||
indexes :organization_id, type: :integer
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
pg_search_scope :search_by_query,
|
||||
against: [:title, :description, :tags],
|
||||
ignoring: :accents,
|
||||
using: {
|
||||
tsearch: {
|
||||
prefix: true,
|
||||
tsvector_column: 'tsv'
|
||||
}
|
||||
}
|
||||
|
||||
attr_reader :member_id
|
||||
|
||||
@ -72,30 +48,6 @@ class Post < ActiveRecord::Base
|
||||
validates :category, presence: true
|
||||
validates :title, presence: true
|
||||
|
||||
def index_document
|
||||
__elasticsearch__.index_document
|
||||
end
|
||||
|
||||
# pass member when doing bulk things
|
||||
def update_or_delete_document(member = nil)
|
||||
member ||= self.member
|
||||
if active && member.try(:active)
|
||||
begin
|
||||
__elasticsearch__.update_document
|
||||
rescue # document was not in the index. TODO: more specifi exception class
|
||||
__elasticsearch__.index_document
|
||||
end
|
||||
else
|
||||
__elasticsearch__.delete_document
|
||||
end
|
||||
rescue # document was not in the index. TODO: more specifi exception class
|
||||
end
|
||||
|
||||
def delete_document
|
||||
__elasticsearch__.delete_document
|
||||
rescue # document was not in the index. TODO: more specifi exception class
|
||||
end
|
||||
|
||||
def as_indexed_json(*)
|
||||
as_json(only: [:title, :description, :tags, :organization_id])
|
||||
end
|
||||
|
||||
@ -35,5 +35,9 @@ module Timeoverflow
|
||||
|
||||
# ActiveJob configuration
|
||||
config.active_job.queue_adapter = :sidekiq
|
||||
|
||||
# Use db/structure.sql with SQL as schema format
|
||||
# This is needed to store in the schema SQL statements not covered by the ORM
|
||||
config.active_record.schema_format = :sql
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
if ENV["ELASTICSEARCH_URL"].present?
|
||||
Elasticsearch::Model.client = Elasticsearch::Client.new host: ENV["ELASTICSEARCH_URL"]
|
||||
end
|
||||
32
db/migrate/20190523213421_add_tsvector_column_to_post.rb
Normal file
32
db/migrate/20190523213421_add_tsvector_column_to_post.rb
Normal file
@ -0,0 +1,32 @@
|
||||
class AddTsvectorColumnToPost < ActiveRecord::Migration
|
||||
def up
|
||||
execute <<-SQL
|
||||
ALTER TABLE posts ADD COLUMN tsv tsvector;
|
||||
|
||||
CREATE FUNCTION posts_trigger() RETURNS trigger AS $$
|
||||
begin
|
||||
new.tsv :=
|
||||
to_tsvector('simple', unaccent(coalesce(new.title::text, ''))) ||
|
||||
to_tsvector('simple', unaccent(coalesce(new.description::text, ''))) ||
|
||||
to_tsvector('simple', unaccent(coalesce(new.tags::text, '')));
|
||||
return new;
|
||||
end
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE
|
||||
ON posts FOR EACH ROW EXECUTE PROCEDURE posts_trigger();
|
||||
SQL
|
||||
|
||||
add_index :posts, :tsv, using: "gin"
|
||||
end
|
||||
|
||||
def down
|
||||
execute <<-SQL
|
||||
DROP TRIGGER tsvectorupdate ON posts;
|
||||
DROP FUNCTION posts_trigger();
|
||||
SQL
|
||||
|
||||
remove_index :posts, :tsv
|
||||
remove_column :posts, :tsv
|
||||
end
|
||||
end
|
||||
9
db/migrate/20190523225323_enable_unaccent_extension.rb
Normal file
9
db/migrate/20190523225323_enable_unaccent_extension.rb
Normal file
@ -0,0 +1,9 @@
|
||||
class EnableUnaccentExtension < ActiveRecord::Migration
|
||||
def up
|
||||
enable_extension "unaccent"
|
||||
end
|
||||
|
||||
def down
|
||||
disable_extension "unaccent"
|
||||
end
|
||||
end
|
||||
221
db/schema.rb
221
db/schema.rb
@ -1,221 +0,0 @@
|
||||
# encoding: UTF-8
|
||||
# This file is auto-generated from the current state of the database. Instead
|
||||
# of editing this file, please use the migrations feature of Active Record to
|
||||
# incrementally modify your database, and then regenerate this schema definition.
|
||||
#
|
||||
# Note that this schema.rb definition is the authoritative source for your
|
||||
# database schema. If you need to create the application database on another
|
||||
# system, you should be using db:schema:load, not running all the migrations
|
||||
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
||||
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20190412163011) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "hstore"
|
||||
|
||||
create_table "accounts", force: :cascade do |t|
|
||||
t.integer "accountable_id"
|
||||
t.string "accountable_type"
|
||||
t.integer "balance", default: 0
|
||||
t.integer "max_allowed_balance"
|
||||
t.integer "min_allowed_balance"
|
||||
t.boolean "flagged"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "organization_id"
|
||||
end
|
||||
|
||||
add_index "accounts", ["accountable_type", "accountable_id"], name: "index_accounts_on_accountable_type_and_accountable_id", using: :btree
|
||||
add_index "accounts", ["organization_id"], name: "index_accounts_on_organization_id", using: :btree
|
||||
|
||||
create_table "active_admin_comments", force: :cascade do |t|
|
||||
t.string "namespace"
|
||||
t.text "body"
|
||||
t.string "resource_id", null: false
|
||||
t.string "resource_type", null: false
|
||||
t.integer "author_id"
|
||||
t.string "author_type"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
add_index "active_admin_comments", ["author_type", "author_id"], name: "index_active_admin_comments_on_author_type_and_author_id", using: :btree
|
||||
add_index "active_admin_comments", ["namespace"], name: "index_active_admin_comments_on_namespace", using: :btree
|
||||
add_index "active_admin_comments", ["resource_type", "resource_id"], name: "index_active_admin_comments_on_resource_type_and_resource_id", using: :btree
|
||||
|
||||
create_table "categories", force: :cascade do |t|
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.hstore "name_translations"
|
||||
end
|
||||
|
||||
create_table "device_tokens", force: :cascade do |t|
|
||||
t.integer "user_id", null: false
|
||||
t.string "token", null: false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
add_index "device_tokens", ["user_id", "token"], name: "index_device_tokens_on_user_id_and_token", unique: true, using: :btree
|
||||
|
||||
create_table "documents", force: :cascade do |t|
|
||||
t.integer "documentable_id"
|
||||
t.string "documentable_type"
|
||||
t.text "title"
|
||||
t.text "content"
|
||||
t.string "label"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
add_index "documents", ["documentable_id", "documentable_type"], name: "index_documents_on_documentable_id_and_documentable_type", using: :btree
|
||||
add_index "documents", ["label"], name: "index_documents_on_label", using: :btree
|
||||
|
||||
create_table "events", force: :cascade do |t|
|
||||
t.integer "action", null: false
|
||||
t.integer "post_id"
|
||||
t.integer "member_id"
|
||||
t.integer "transfer_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
add_index "events", ["member_id"], name: "index_events_on_member_id", where: "(member_id IS NOT NULL)", using: :btree
|
||||
add_index "events", ["post_id"], name: "index_events_on_post_id", where: "(post_id IS NOT NULL)", using: :btree
|
||||
add_index "events", ["transfer_id"], name: "index_events_on_transfer_id", where: "(transfer_id IS NOT NULL)", using: :btree
|
||||
|
||||
create_table "members", force: :cascade do |t|
|
||||
t.integer "user_id"
|
||||
t.integer "organization_id"
|
||||
t.boolean "manager"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.date "entry_date"
|
||||
t.integer "member_uid"
|
||||
t.boolean "active", default: true
|
||||
end
|
||||
|
||||
add_index "members", ["organization_id"], name: "index_members_on_organization_id", using: :btree
|
||||
add_index "members", ["user_id"], name: "index_members_on_user_id", using: :btree
|
||||
|
||||
create_table "movements", force: :cascade do |t|
|
||||
t.integer "account_id"
|
||||
t.integer "transfer_id"
|
||||
t.integer "amount"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
add_index "movements", ["account_id"], name: "index_movements_on_account_id", using: :btree
|
||||
add_index "movements", ["transfer_id"], name: "index_movements_on_transfer_id", using: :btree
|
||||
|
||||
create_table "organizations", force: :cascade do |t|
|
||||
t.string "name", limit: 255, null: false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.integer "reg_number_seq"
|
||||
t.string "theme"
|
||||
t.string "email"
|
||||
t.string "phone"
|
||||
t.string "web"
|
||||
t.text "public_opening_times"
|
||||
t.text "description"
|
||||
t.text "address"
|
||||
t.string "neighborhood"
|
||||
t.string "city"
|
||||
t.string "domain"
|
||||
end
|
||||
|
||||
add_index "organizations", ["name"], name: "index_organizations_on_name", unique: true, using: :btree
|
||||
|
||||
create_table "posts", force: :cascade do |t|
|
||||
t.string "title"
|
||||
t.string "type"
|
||||
t.integer "category_id"
|
||||
t.integer "user_id"
|
||||
t.text "description"
|
||||
t.date "start_on"
|
||||
t.date "end_on"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.text "tags", array: true
|
||||
t.integer "organization_id"
|
||||
t.boolean "active", default: true
|
||||
t.boolean "is_group", default: false
|
||||
end
|
||||
|
||||
add_index "posts", ["category_id"], name: "index_posts_on_category_id", using: :btree
|
||||
add_index "posts", ["organization_id"], name: "index_posts_on_organization_id", using: :btree
|
||||
add_index "posts", ["tags"], name: "index_posts_on_tags", using: :gin
|
||||
add_index "posts", ["user_id"], name: "index_posts_on_user_id", using: :btree
|
||||
|
||||
create_table "push_notifications", force: :cascade do |t|
|
||||
t.integer "event_id", null: false
|
||||
t.integer "device_token_id", null: false
|
||||
t.datetime "processed_at"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.string "title", default: "", null: false
|
||||
t.string "body", default: "", null: false
|
||||
t.json "data", default: {}, null: false
|
||||
end
|
||||
|
||||
create_table "transfers", force: :cascade do |t|
|
||||
t.integer "post_id"
|
||||
t.text "reason"
|
||||
t.integer "operator_id"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
add_index "transfers", ["operator_id"], name: "index_transfers_on_operator_id", using: :btree
|
||||
add_index "transfers", ["post_id"], name: "index_transfers_on_post_id", using: :btree
|
||||
|
||||
create_table "users", force: :cascade do |t|
|
||||
t.string "username", null: false
|
||||
t.string "email", null: false
|
||||
t.date "date_of_birth"
|
||||
t.string "identity_document"
|
||||
t.string "phone"
|
||||
t.string "alt_phone"
|
||||
t.text "address"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.datetime "deleted_at"
|
||||
t.string "gender"
|
||||
t.text "description"
|
||||
t.boolean "active", default: true
|
||||
t.datetime "terms_accepted_at"
|
||||
t.string "encrypted_password", default: "", null: false
|
||||
t.string "reset_password_token"
|
||||
t.datetime "reset_password_sent_at"
|
||||
t.datetime "remember_created_at"
|
||||
t.integer "sign_in_count", default: 0
|
||||
t.datetime "current_sign_in_at"
|
||||
t.datetime "last_sign_in_at"
|
||||
t.string "current_sign_in_ip"
|
||||
t.string "last_sign_in_ip"
|
||||
t.string "confirmation_token"
|
||||
t.datetime "confirmed_at"
|
||||
t.datetime "confirmation_sent_at"
|
||||
t.string "unconfirmed_email"
|
||||
t.integer "failed_attempts", default: 0
|
||||
t.string "unlock_token"
|
||||
t.datetime "locked_at"
|
||||
t.string "locale", default: "es"
|
||||
t.boolean "notifications", default: true
|
||||
t.boolean "push_notifications", default: true, null: false
|
||||
end
|
||||
|
||||
add_index "users", ["email"], name: "index_users_on_email", using: :btree
|
||||
|
||||
add_foreign_key "accounts", "organizations"
|
||||
add_foreign_key "events", "members", name: "events_member_id_fkey"
|
||||
add_foreign_key "events", "posts", name: "events_post_id_fkey"
|
||||
add_foreign_key "events", "transfers", name: "events_transfer_id_fkey"
|
||||
add_foreign_key "push_notifications", "device_tokens"
|
||||
add_foreign_key "push_notifications", "events"
|
||||
end
|
||||
1141
db/structure.sql
Normal file
1141
db/structure.sql
Normal file
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@
|
||||
require 'elasticsearch/rails/tasks/import'
|
||||
@ -12,46 +12,111 @@ RSpec.describe OffersController, type: :controller do
|
||||
organization: organization,
|
||||
category: test_category)
|
||||
end
|
||||
let!(:other_offer) do
|
||||
Fabricate(:offer,
|
||||
user: another_member.user,
|
||||
organization: organization,
|
||||
category: test_category)
|
||||
end
|
||||
|
||||
describe "GET #index" do
|
||||
context "with a logged user" do
|
||||
it "populates an array of offers" do
|
||||
login(another_member.user)
|
||||
|
||||
get "index"
|
||||
expect(assigns(:offers)).to eq([offer])
|
||||
get :index
|
||||
|
||||
expect(assigns(:offers)).to eq([other_offer, offer])
|
||||
end
|
||||
|
||||
context "when one offer is not active" do
|
||||
before do
|
||||
other_offer.active = false
|
||||
other_offer.save!
|
||||
end
|
||||
|
||||
it "only returns active offers" do
|
||||
login(another_member.user)
|
||||
|
||||
get :index
|
||||
|
||||
expect(assigns(:offers)).to eq([offer])
|
||||
end
|
||||
end
|
||||
|
||||
context "when one offer's user is not active" do
|
||||
before do
|
||||
member.active = false
|
||||
member.save!
|
||||
end
|
||||
|
||||
it "only returns offers from active users" do
|
||||
login(another_member.user)
|
||||
|
||||
get :index
|
||||
|
||||
expect(assigns(:offers)).to eq([other_offer])
|
||||
end
|
||||
end
|
||||
end
|
||||
context "with another organization" do
|
||||
it "skips the original org's offers" do
|
||||
login(yet_another_member.user)
|
||||
get "index"
|
||||
|
||||
get :index
|
||||
|
||||
expect(assigns(:offers)).to eq([])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET #index (search)" do
|
||||
before { login(another_member.user) }
|
||||
before do
|
||||
Offer.__elasticsearch__.create_index!(force: true)
|
||||
|
||||
# Import any already existing model into the index
|
||||
# for instance the ones that have been created in upper
|
||||
# `let!` or `before` blocks
|
||||
Offer.__elasticsearch__.import(force: true, refresh: true)
|
||||
offer.title = "Queridos compañeros"
|
||||
offer.save!
|
||||
end
|
||||
|
||||
it "populates an array of offers" do
|
||||
login(another_member.user)
|
||||
get :index, q: 'compañeros'
|
||||
|
||||
get "index", q: offer.title.split(/\s/).first
|
||||
expect(assigns(:offers)).to eq([offer])
|
||||
end
|
||||
|
||||
# @offers is a wrapper from Elasticsearch. It's iterator-equivalent to
|
||||
# the underlying query from the database.
|
||||
expect(assigns(:offers)).to be_a Elasticsearch::Model::Response::Records
|
||||
expect(assigns(:offers).size).to eq 1
|
||||
expect(assigns(:offers)[0]).to eq offer
|
||||
expect(assigns(:offers).to_a).to eq([offer])
|
||||
it "allows to search by partial word" do
|
||||
get :index, q: 'compañ'
|
||||
|
||||
expect(assigns(:offers)).to eq([offer])
|
||||
end
|
||||
|
||||
context "when one offer is not active" do
|
||||
before do
|
||||
other_offer.active = false
|
||||
other_offer.save!
|
||||
end
|
||||
|
||||
it "only returns active offers" do
|
||||
login(another_member.user)
|
||||
|
||||
get :index
|
||||
|
||||
expect(assigns(:offers)).to eq([offer])
|
||||
end
|
||||
end
|
||||
|
||||
context "when one offer's user is not active" do
|
||||
before do
|
||||
member.active = false
|
||||
member.save!
|
||||
end
|
||||
|
||||
it "only returns offers from active users" do
|
||||
login(another_member.user)
|
||||
|
||||
get :index
|
||||
|
||||
expect(assigns(:offers)).to eq([other_offer])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user