Adding search/order + Show need page + comments

This commit is contained in:
Nicolas VARROT 2015-12-04 14:34:12 +01:00
parent 22b86c191f
commit 1fd0e4c624
32 changed files with 504 additions and 149 deletions

View File

@ -70,3 +70,5 @@ gem "geocoder"
gem "paranoia", "~> 2.0" gem "paranoia", "~> 2.0"
gem 'workflow', '~> 1.2.0' gem 'workflow', '~> 1.2.0'
gem 'elasticsearch-model', git: 'git://github.com/elasticsearch/elasticsearch-rails.git'

View File

@ -1,3 +1,12 @@
GIT
remote: git://github.com/elasticsearch/elasticsearch-rails.git
revision: 5f32e484a6d0458f26dc9acfa9dd5fed4e5d6453
specs:
elasticsearch-model (0.1.8)
activesupport (> 3)
elasticsearch (> 0.4)
hashie
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
@ -69,8 +78,18 @@ GEM
columnize (0.9.0) columnize (0.9.0)
debug_inspector (0.0.2) debug_inspector (0.0.2)
debugger-linecache (1.2.0) debugger-linecache (1.2.0)
elasticsearch (1.0.14)
elasticsearch-api (= 1.0.14)
elasticsearch-transport (= 1.0.14)
elasticsearch-api (1.0.14)
multi_json
elasticsearch-transport (1.0.14)
faraday
multi_json
erubis (2.7.0) erubis (2.7.0)
execjs (2.3.0) execjs (2.3.0)
faraday (0.9.2)
multipart-post (>= 1.2, < 3)
formtastic (2.3.0) formtastic (2.3.0)
actionpack (>= 3.0) actionpack (>= 3.0)
formtastic-bootstrap (3.0.0) formtastic-bootstrap (3.0.0)
@ -87,6 +106,7 @@ GEM
haml (>= 3.1, < 5.0) haml (>= 3.1, < 5.0)
html2haml (>= 1.0.1) html2haml (>= 1.0.1)
railties (>= 4.0.1) railties (>= 4.0.1)
hashie (3.4.3)
highline (1.7.2) highline (1.7.2)
hike (1.2.3) hike (1.2.3)
html2haml (2.0.0) html2haml (2.0.0)
@ -118,6 +138,7 @@ GEM
mini_portile (0.6.2) mini_portile (0.6.2)
minitest (5.5.1) minitest (5.5.1)
multi_json (1.10.1) multi_json (1.10.1)
multipart-post (2.0.0)
mysql2 (0.3.18) mysql2 (0.3.18)
net-scp (1.2.1) net-scp (1.2.1)
net-ssh (>= 2.6.5) net-ssh (>= 2.6.5)
@ -228,6 +249,7 @@ DEPENDENCIES
capistrano (= 2.15.5) capistrano (= 2.15.5)
carrierwave carrierwave
coffee-rails (~> 4.1.0) coffee-rails (~> 4.1.0)
elasticsearch-model!
formtastic (= 2.3.0) formtastic (= 2.3.0)
formtastic-bootstrap formtastic-bootstrap
geocoder geocoder

View File

@ -22,6 +22,7 @@
@flash_delay = -> @flash_delay = ->
$("#flashs").find(".alert").each -> $("#flashs").find(".alert").each ->

View File

@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View File

@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View File

@ -0,0 +1,3 @@
// Place all the styles related to the public/messages controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -1,36 +1,98 @@
.btn-square{
border-radius: 0px;
}
.side-menu{
h3{
margin-top:0px;
}
}
.show-need{
position: relative;
.info{
color:rgb(163, 159, 159);
}
p.description{
margin-bottom:30px;
}
.message-item{
background: #eeeded;
}
.counters{
position:absolute;
left:0px;
bottom:0px;
padding-left:5px;
padding-bottom:5px;
.item{
display:inline;
margin-left:0px;
font-size:20px;
}
}
}
.need-item{ .need-item{
height: 150px; height: 150px;
background-color:#fff; background-color:#fff;
padding-top:30px; padding-top:30px;
p{ position:relative;
p.description{
font-size:12px; font-size:12px;
color:rgb(163, 159, 159); color:rgb(163, 159, 159);
} }
p.info{
font-size:10px;
color:rgb(163, 159, 159);
}
.counters{
position:absolute;
left:0px;
bottom:0px;
padding-left:5px;
padding-bottom:5px;
.item{
display:inline;
margin-left:10px;
font-size:18px;
}
}
span{ span{
background-color: #ede8e8; background-color: #ede8e8;
position:absolute; position:absolute;
padding:5px; padding:5px;
top:0px; top:0px;
right:15px; right:0px;
.time{ .info{
color:rgb(121, 120, 120); color:rgb(121, 120, 120);
text-align:right; text-align:right;
font-size:10px; font-size:10px;
} }
} }
margin-bottom:30px; margin-bottom:50px;
h3{ h4{
margin-top:0px; margin-top:0px;
margin-bottom:0px;
} }
.btn{ .btn{
border-radius: 0px; border-radius: 0px;
position:absolute; position:absolute;
right:15px; right:0px;
bottom:30px; bottom:0px;
} }
} }

View File

@ -0,0 +1,3 @@
// Place all the styles related to the public/needs controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View File

@ -40,7 +40,7 @@ class Admin::NeedsController < ApplicationController
flash[:notice] = "Besoin validé avec succès" flash[:notice] = "Besoin validé avec succès"
CustomerMailer.validate_need(@need).deliver CustomerMailer.validate_need(@need).deliver
else else
flash[:error] = "L'état actuel de ce besoin ne permet sa validation" flash[:error] = "L'état actuel de ce besoin ne permet pas sa validation"
end end
redirect_to admin_needs_path redirect_to admin_needs_path
end end

View File

@ -0,0 +1,28 @@
class Public::MessagesController < ApplicationController
layout "public"
before_filter :auth_customer
def index
need = Need.find(params[:need_id])
end
def create
need = Need.find(params[:need_id])
@message = need.messages.create(comment_params)
@message.customer = current_customer
if(@message.save)
flash[:notice] = "Commentaire envoyé."
end
redirect_to public_need_path(need)
end
def comment_params
params.require(:message).permit(:content)
end
end

View File

@ -5,7 +5,58 @@ class Public::NeedsController < ApplicationController
before_filter :auth_customer before_filter :auth_customer
def index def index
# Get only public needs
@needs = Need.shared @needs = Need.shared
# filters default value
params[:o] ||= 'created-desc'
# Include search in the query
if(params[:q] != '')
@needs = @needs.search(params[:q])
end
# Include order in the query
case params[:o]
when 'alpha-asc'
@needs = @needs.order(title: :asc)
when 'alpha-desc'
@needs = @needs.order(title: :desc)
when 'wishes-asc'
@needs = @needs.with_wishes_count.order('wishes_count ASC')
when 'wishes-desc'
@needs = @needs.with_wishes_count.order('wishes_count DESC')
when 'created-asc'
@needs = @needs.order(created_at: :asc)
when 'created-desc'
@needs = @needs.order(created_at: :desc)
when 'comments-asc'
@needs = @needs.with_messages_count.order('messages_count ASC')
when 'comments-desc'
@needs = @needs.with_messages_count.order('messages_count DESC')
end
# Paginate
@needs = @needs.page(params[:page]).per(6)
# Define order select options
@orders = {
"Les plus récents" => 'created-desc',
"Les plus anciens" => 'created-asc',
"Nombre d'intérêts décroissants" => 'wishes-desc',
"Nombre d'intérêts croissants" => 'wishes-asc' ,
"Nombre de commentaires décroissants" => 'comments-desc',
"Nombre de commentaires croissants" => 'comments-asc',
"Alphabétique (de A à Z)" => 'alpha-asc',
"Alphabétique (de Z à A)" => 'alpha-desc'
}
end end
def new def new
@ -24,6 +75,13 @@ class Public::NeedsController < ApplicationController
@need = Need.find(params[:id]) @need = Need.find(params[:id])
end end
def show
@need = Need.find(params[:id])
@comment = Message.new()
@comments = @need.messages.order(created_at: :desc).page params[:page]
end
def update def update
@need = Need.find(params[:id]) @need = Need.find(params[:id])
if @need.update_attributes(need_params) if @need.update_attributes(need_params)
@ -63,7 +121,7 @@ class Public::NeedsController < ApplicationController
flash[:notice] = "Vous avez signalé votre intérêt pour ce besoin" flash[:notice] = "Vous avez signalé votre intérêt pour ce besoin"
else else
@need.customers.delete(current_customer) @need.customers.delete(current_customer)
flash[:error] = "Vous n'être plus marqué comme intéressé par ce besoin" flash[:error] = "Vous n'êtes maintenant plus intéressé par ce besoin"
end end
redirect_to :back redirect_to :back
end end

View File

@ -0,0 +1,2 @@
module Public::MessagesHelper
end

View File

@ -0,0 +1,2 @@
module Public::NeedsHelper
end

View File

@ -3,7 +3,7 @@ class Customer < ActiveRecord::Base
# Relationships # Relationships
has_many :owned_needs, foreign_key: 'author_id', class_name: 'Need' has_many :owned_needs, foreign_key: 'author_id', class_name: 'Need'
has_many :wishes has_many :wishes, dependent: :destroy
has_many :needs, -> { uniq }, through: :wishes has_many :needs, -> { uniq }, through: :wishes
has_many :customer_favs has_many :customer_favs
@ -141,6 +141,10 @@ class Customer < ActiveRecord::Base
end end
def anonyme_nick
"Utilisateur#{id}"
end
def mlm_children_id_by_levels def mlm_children_id_by_levels
self.mlm_detail_ids[:mlm_children_id_by_levels] self.mlm_detail_ids[:mlm_children_id_by_levels]
end end

7
app/models/message.rb Normal file
View File

@ -0,0 +1,7 @@
class Message < ActiveRecord::Base
belongs_to :customer
belongs_to :need
paginates_per 5
validates :content, :presence => true, length: {within: 1..512}
end

View File

@ -1,21 +1,37 @@
require 'elasticsearch/model'
class Need < ActiveRecord::Base class Need < ActiveRecord::Base
include Workflow include Workflow
include Elasticsearch::Model
include Elasticsearch::Model::Callbacks
scope :shared, -> { scope :shared, -> {
where(state: ["verified", "negociating", "negociated", "failed"]) where(state: ["verified", "negociating", "negociated", "failed"])
} }
scope :top, -> { joins('left join wishes on wishes.need_id = needs.id') scope :with_wishes_count, -> { joins('left join wishes on wishes.need_id = needs.id')
.select('needs.*, count(wishes.id) as wishes_count') .select('needs.*, count(wishes.id) as wishes_count')
.group("needs.id") .group("needs.id")
.order("wishes_count DESC") } }
scope :with_messages_count, -> { joins('left join messages on messages.need_id = needs.id')
.select('needs.*, count(messages.id) as messages_count')
.group("needs.id")
}
scope :search, -> (search) {
where('title LIKE ?', "%#{search}%")
}
workflow_column :state workflow_column :state
max_paginates_per 10
acts_as_paranoid acts_as_paranoid
has_many :wishes has_many :wishes, dependent: :destroy
has_many :customers, -> { uniq }, through: :wishes has_many :customers, -> { uniq }, through: :wishes
has_many :messages, dependent: :destroy
validates :title, :presence => true, length: {within: 4..128} validates :title, :presence => true, length: {within: 4..128}
validates :description, presence: true, length: {maximum: 65535} validates :description, presence: true, length: {maximum: 65535}
@ -46,7 +62,7 @@ class Need < ActiveRecord::Base
when 'created' when 'created'
"En attente de validation" "En attente de validation"
when 'verified' when 'verified'
"Validé" "Pas encore négocié"
when 'refused' when 'refused'
"Refusé" "Refusé"
when 'negociating' when 'negociating'

View File

@ -9,7 +9,4 @@
%tr.submit_tr %tr.submit_tr
%td=link_to "Annuler", admin_data_file_path(:id => @data_file.id, :manager => params[:manager], :multiple => params[:multiple]), :remote => true %td=link_to "Annuler", admin_data_file_path(:id => @data_file.id, :manager => params[:manager], :multiple => params[:multiple]), :remote => true
%td %td
=form.submit "Sauvegarder" =form.submit "Sauvegarder"

View File

@ -10,5 +10,3 @@
%tbody %tbody
=render @needs =render @needs
.pagination= paginate @needs

View File

@ -0,0 +1,6 @@
.white.padding.message-item
%h4= i(:"user") + " " + message.customer.anonyme_nick
%p.info=i(:"clock-o") + " Posté le #{message.created_at.strftime('%d/%m/%Y à %H:%M')}, il y a #{time_ago_in_words(message.created_at)}"
%p= message.content

View File

@ -1,16 +1,25 @@
.col-md-6 .col-md-6
.padding.need-item .padding.need-item
%h3=need.title.upcase %h4
=link_to need.title.upcase, public_need_path(need)
%p.info=i(:"clock-o") + " Ajouté il y a #{time_ago_in_words(need.created_at)} par #{need.author.anonyme_nick}"
%span %span
.time= i(:"clock-o") + " Ajouté il y a #{time_ago_in_words(need.created_at)}" .info=i(:"info-circle") + " " + need.human_state
%p=truncate(need.description, length: 100)
%p.description=truncate(need.description, length: 100)
.counters
.item=i(:"hand-paper-o") + " " + need.wishes.length.to_s
.item=i(:"comment-o") + " " + need.messages.length.to_s
-if(need.customers.include?(current_customer)) -if(need.customers.include?(current_customer))
=link_to i(:"hand-grab-o") + " Ça ne m'intéresse plus", wish_public_need_path(need) , :class => "btn btn-danger pull-right" =link_to i(:"check") + " Intéressé", wish_public_need_path(need) , :class => "btn btn-success pull-right"
-else -else
=link_to i(:"hand-paper-o") + " Ça m'intéresse", wish_public_need_path(need) , :class => "btn btn-success pull-right" =link_to i(:"hand-paper-o") + " Ça m'intéresse !", wish_public_need_path(need) , :class => "btn btn-primary pull-right"
.clear .clear

View File

@ -4,6 +4,25 @@
=render collection: @needs, partial: 'need_item', as: :need =render collection: @needs, partial: 'need_item', as: :need
.clear
.pagination= paginate @needs
.row.col-md-3 .row.col-md-3
.white .white.side-menu
%h3 Sidebar = semantic_form_for :search, :html => {id: :search_form, :method => :get } do |f|
%h4 Recherche
= f.inputs do
= f.input :q, :as => :search, label: false, input_html: {value: params[:q], :name => 'q' }, placeholder: "Rechercher un besoin"
=f.submit "Rechercher", :class => "btn btn-primary pull-right"
.clear
%h4 Ordonner par
= f.inputs do
= f.input :o, as: :order, selected: params[:o], input_html: {:name => 'o' }, label: false, :include_blank => false , :as => :select, :collection => @orders
.clear
:javascript
$('#search_o').change(function(){$('#search_form').submit()})

View File

@ -0,0 +1,38 @@
.center.white
.show-need
%h1= @need.title.upcase
%p.info=i(:"clock-o") + " Ajouté il y a #{time_ago_in_words(@need.created_at)} par #{@need.author.anonyme_nick}"
%p.description= @need.description
.clear
.counters
-if(@need.wishes.length > 0)
.item=i(:"hand-paper-o") + " " + " #{pluralize(@need.wishes.length, 'Organisation')} #{"intéressé".pluralize(@need.wishes.length)} par ce besoin"
-else
.item=i(:"hand-paper-o") + " Aucune organisation n'est intéressé par ce besoin"
-if(@need.customers.include?(current_customer))
=link_to i(:"check") + " Intéressé", wish_public_need_path(@need) , :class => "btn btn-square btn-lg btn-success pull-right"
-else
=link_to i(:"hand-paper-o") + " Ça m'intéresse !", wish_public_need_path(@need) , :class => "btn btn-square btn-lg btn-primary pull-right"
.clear
%hr
= semantic_form_for [:public, @need, @comment ], :html => {id: :message_form, :method => :post } do |f|
%h4 Poster un commentaire
= f.inputs do
= f.input :content, as: :text, label: false, rows: 5, :input_html => {:style => "height:100px;"}
=f.submit "Envoyer", :class => "btn btn-square btn-primary pull-right"
.clear
%h3= i(:"comment-o") + " #{pluralize(@need.messages.count, 'Commentaire')} pour ce besoin"
=render collection: @comments, partial: 'message'
.pagination= paginate @comments

View File

@ -89,6 +89,7 @@ Rails.application.routes.draw do
get 'my_account/reconfirm', :as => "reconfirm_email" get 'my_account/reconfirm', :as => "reconfirm_email"
resources :needs do resources :needs do
resources :messages
member do member do
get 'wish', as: 'wish' get 'wish', as: 'wish'
end end

View File

@ -0,0 +1,5 @@
class AddIndexToNeed < ActiveRecord::Migration
def change
add_index :needs, :title
end
end

View File

@ -0,0 +1,11 @@
class CreateMessages < ActiveRecord::Migration
def change
create_table :messages do |t|
t.timestamps null: false
t.references :customer
t.references :need
t.text :content
end
end
end

View File

@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20151202165807) do ActiveRecord::Schema.define(version: 20151203185210) do
create_table "admins", force: :cascade do |t| create_table "admins", force: :cascade do |t|
t.string "name", limit: 255 t.string "name", limit: 255
@ -382,6 +382,14 @@ ActiveRecord::Schema.define(version: 20151202165807) do
t.datetime "updated_at" t.datetime "updated_at"
end end
create_table "messages", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "customer_id", limit: 4
t.integer "need_id", limit: 4
t.text "content", limit: 65535
end
create_table "needs", force: :cascade do |t| create_table "needs", force: :cascade do |t|
t.string "title", limit: 255 t.string "title", limit: 255
t.text "description", limit: 65535 t.text "description", limit: 65535
@ -394,6 +402,7 @@ ActiveRecord::Schema.define(version: 20151202165807) do
add_index "needs", ["author_id"], name: "index_needs_on_author_id", using: :btree add_index "needs", ["author_id"], name: "index_needs_on_author_id", using: :btree
add_index "needs", ["deleted_at"], name: "index_needs_on_deleted_at", using: :btree add_index "needs", ["deleted_at"], name: "index_needs_on_deleted_at", using: :btree
add_index "needs", ["title"], name: "index_needs_on_title", using: :btree
create_table "newsgroups", force: :cascade do |t| create_table "newsgroups", force: :cascade do |t|
t.string "name", limit: 255 t.string "name", limit: 255

View File

@ -0,0 +1,7 @@
require 'test_helper'
class MessagesControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View File

@ -0,0 +1,7 @@
require 'test_helper'
class Public::MessagesControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View File

@ -0,0 +1,7 @@
require 'test_helper'
class Public::NeedsControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

View File

@ -0,0 +1,7 @@
require 'test_helper'
class PublicmessagesControllerTest < ActionController::TestCase
# test "the truth" do
# assert true
# end
end

11
test/fixtures/messages.yml vendored Normal file
View File

@ -0,0 +1,11 @@
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
# This model initially had no columns defined. If you add columns to the
# model remove the '{}' from the fixture names and add the columns immediately
# below each fixture, per the syntax in the comments below
#
one: {}
# column: value
#
two: {}
# column: value

View File

@ -0,0 +1,7 @@
require 'test_helper'
class MessageTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end