solidus_reviews 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +18 -0
  5. data/CONTRIBUTING.md +28 -0
  6. data/Gemfile +14 -0
  7. data/LICENSE.md +26 -0
  8. data/README.md +93 -0
  9. data/Rakefile +21 -0
  10. data/app/assets/images/store/reviews/delete.gif +0 -0
  11. data/app/assets/images/store/reviews/star.gif +0 -0
  12. data/app/assets/javascripts/spree/backend/solidus_reviews.js +7 -0
  13. data/app/assets/javascripts/spree/frontend/solidus_reviews.js +7 -0
  14. data/app/assets/stylesheets/spree/backend/solidus_reviews.css +3 -0
  15. data/app/assets/stylesheets/spree/frontend/solidus_reviews.scss +83 -0
  16. data/app/controllers/spree/admin/feedback_reviews_controller.rb +6 -0
  17. data/app/controllers/spree/admin/review_settings_controller.rb +21 -0
  18. data/app/controllers/spree/admin/reviews_controller.rb +34 -0
  19. data/app/controllers/spree/feedback_reviews_controller.rb +41 -0
  20. data/app/controllers/spree/products_controller_decorator.rb +5 -0
  21. data/app/controllers/spree/reviews_controller.rb +48 -0
  22. data/app/helpers/spree/reviews_helper.rb +17 -0
  23. data/app/models/spree/feedback_review.rb +17 -0
  24. data/app/models/spree/product_decorator.rb +21 -0
  25. data/app/models/spree/review.rb +36 -0
  26. data/app/models/spree/reviews_ability.rb +17 -0
  27. data/app/models/spree/reviews_configuration.rb +26 -0
  28. data/app/overrides/add_reviews_after_product_properties.rb +5 -0
  29. data/app/overrides/add_reviews_tab_to_admin.rb +4 -0
  30. data/app/overrides/add_reviews_to_admin_configuration_sidebar.rb +5 -0
  31. data/app/views/spree/admin/feedback_reviews/index.html.erb +44 -0
  32. data/app/views/spree/admin/review_settings/edit.html.erb +40 -0
  33. data/app/views/spree/admin/reviews/_form.html.erb +22 -0
  34. data/app/views/spree/admin/reviews/edit.html.erb +26 -0
  35. data/app/views/spree/admin/reviews/index.html.erb +111 -0
  36. data/app/views/spree/feedback_reviews/_form.html.erb +13 -0
  37. data/app/views/spree/feedback_reviews/_summary.html.erb +6 -0
  38. data/app/views/spree/feedback_reviews/create.js.erb +7 -0
  39. data/app/views/spree/reviews/_form.html.erb +34 -0
  40. data/app/views/spree/reviews/_stars.html.erb +13 -0
  41. data/app/views/spree/reviews/index.html.erb +1 -0
  42. data/app/views/spree/reviews/new.html.erb +3 -0
  43. data/app/views/spree/shared/_rating.html.erb +15 -0
  44. data/app/views/spree/shared/_review.html.erb +28 -0
  45. data/app/views/spree/shared/_review_summary.html.erb +9 -0
  46. data/app/views/spree/shared/_reviews.html.erb +15 -0
  47. data/app/views/spree/shared/_shortrating.html.erb +9 -0
  48. data/bin/rails +5 -0
  49. data/config/initializers/constants.rb +1 -0
  50. data/config/initializers/load_preferences.rb +5 -0
  51. data/config/locales/de-CH.yml +68 -0
  52. data/config/locales/de.yml +68 -0
  53. data/config/locales/en-GB.yml +68 -0
  54. data/config/locales/en.yml +67 -0
  55. data/config/locales/es.yml +68 -0
  56. data/config/locales/fr.yml +68 -0
  57. data/config/locales/pl.yml +72 -0
  58. data/config/locales/pt-BR.yml +68 -0
  59. data/config/locales/pt.yml +69 -0
  60. data/config/locales/ro.yml +76 -0
  61. data/config/locales/ru.yml +73 -0
  62. data/config/locales/sv.yml +66 -0
  63. data/config/locales/tr.yml +68 -0
  64. data/config/locales/uk.yml +75 -0
  65. data/config/locales/zh-CN.yml +65 -0
  66. data/config/locales/zh-TW.yml +65 -0
  67. data/config/routes.rb +17 -0
  68. data/db/migrate/20081020220724_create_reviews.rb +18 -0
  69. data/db/migrate/20101222083309_create_feedback_reviews.rb +17 -0
  70. data/db/migrate/20110406083603_add_rating_to_products.rb +21 -0
  71. data/db/migrate/20110606150524_add_user_to_reviews.rb +9 -0
  72. data/db/migrate/20110806093221_add_ip_address_to_reviews.rb +9 -0
  73. data/db/migrate/20120110172331_namespace_tables.rb +6 -0
  74. data/db/migrate/20120123141326_recalculate_ratings.rb +20 -0
  75. data/db/migrate/20120712182514_add_locale_to_reviews.rb +9 -0
  76. data/db/migrate/20120712182627_add_locale_to_feedback_reviews.rb +9 -0
  77. data/db/migrate/20140703200946_add_show_identifier_to_reviews.rb +6 -0
  78. data/db/sample/ratings.yml +16 -0
  79. data/db/sample/reviews.yml +59 -0
  80. data/lib/generators/solidus_reviews/install/install_generator.rb +30 -0
  81. data/lib/solidus_reviews/factories/feedback_review_factory.rb +8 -0
  82. data/lib/solidus_reviews/factories/review_factory.rb +20 -0
  83. data/lib/solidus_reviews/factories.rb +5 -0
  84. data/lib/solidus_reviews.rb +6 -0
  85. data/lib/spree_reviews/engine.rb +17 -0
  86. data/solidus_reviews.gemspec +35 -0
  87. data/spec/controllers/admin/feedback_reviews_controller_spec.rb +29 -0
  88. data/spec/controllers/admin/review_settings_controller_spec.rb +57 -0
  89. data/spec/controllers/admin/reviews_controller_spec.rb +63 -0
  90. data/spec/controllers/feedback_reviews_controller_spec.rb +71 -0
  91. data/spec/controllers/products_controller_spec.rb +9 -0
  92. data/spec/controllers/reviews_controller_spec.rb +136 -0
  93. data/spec/features/admin_spec.rb +35 -0
  94. data/spec/features/reviews_spec.rb +122 -0
  95. data/spec/helpers/review_helper_spec.rb +28 -0
  96. data/spec/models/feedback_review_spec.rb +78 -0
  97. data/spec/models/product_spec.rb +62 -0
  98. data/spec/models/review_spec.rb +168 -0
  99. data/spec/models/reviews_ability_spec.rb +46 -0
  100. data/spec/models/reviews_configuration_spec.rb +45 -0
  101. data/spec/spec_helper.rb +55 -0
  102. data/vendor/assets/javascripts/jquery.rating.js +376 -0
  103. metadata +357 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f0b51c02c6474636cf9398f1e7c51ca332eadba8
4
+ data.tar.gz: 0fb923dfe70a7b22fed4ba65aedea239d73101bb
5
+ SHA512:
6
+ metadata.gz: e3257de4d8a2956c07f16e710559ed37505ffe456d2a1ad65b99ac70419556d92f112c1510a24374c96077db15d47127e32e5fd48c4de605ccfd44d4b352930b
7
+ data.tar.gz: ff881a9a9c17757c84aaff1877efde25378df3d22506bd87667b1918db9cf73459f75175ebf446b62187ad71126274a68a0075b1a3778b24be52b8e74f6f2685
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ *.gem
2
+ *.swp
3
+ .bundle
4
+ .idea
5
+ .DS_Store
6
+ Gemfile.lock
7
+ pkg/*
8
+ spec/dummy
9
+ coverage
10
+ .rvmrc
11
+ .ruby-version
12
+ .ruby-gemset
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ -f documentation
data/.travis.yml ADDED
@@ -0,0 +1,18 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.3
4
+ sudo: false
5
+ cache: bundler
6
+ only: master
7
+ env:
8
+ matrix:
9
+ - SOLIDUS_BRANCH=v1.0 DB=mysql
10
+ - SOLIDUS_BRANCH=v1.0 DB=postgresql
11
+ - SOLIDUS_BRANCH=v1.1 DB=mysql
12
+ - SOLIDUS_BRANCH=v1.1 DB=postgresql
13
+ - SOLIDUS_BRANCH=v1.2 DB=mysql
14
+ - SOLIDUS_BRANCH=v1.2 DB=postgresql
15
+ - SOLIDUS_BRANCH=v1.3 DB=mysql
16
+ - SOLIDUS_BRANCH=v1.3 DB=postgresql
17
+ - SOLIDUS_BRANCH=v1.4 DB=mysql
18
+ - SOLIDUS_BRANCH=v1.4 DB=postgresql
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,28 @@
1
+ # Contributing
2
+
3
+ In the spirit of [free software][1], **everyone** is encouraged to help improve this project.
4
+
5
+ Here are some ways *you* can contribute:
6
+
7
+ - by using prerelease versions
8
+ - by reporting [bugs][2]
9
+ - by suggesting new features
10
+ - by writing translations
11
+ - by writing or editing documentation
12
+ - by writing specifications
13
+ - by writing code (*no patch is too small*: fix typos, add comments, clean up inconsistent whitespace)
14
+ - by refactoring code
15
+ - by resolving [issues][2]
16
+ - by reviewing patches
17
+
18
+ Starting point:
19
+
20
+ - Fork the repo
21
+ - Clone your repo
22
+ - Run `bundle install`
23
+ - Run `bundle exec rake test_app` to create the test application in `spec/test_app`
24
+ - Ensure specs pass by running `bundle exec rspec spec`
25
+ - Submit your pull request
26
+
27
+ [1]: http://www.fsf.org/licensing/essays/free-sw.html
28
+ [2]: https://github.com/spree-contrib/spree_reviews/issues
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source 'https://rubygems.org'
2
+
3
+ branch = ENV.fetch('SOLIDUS_BRANCH', 'v1.4')
4
+ gem "solidus", github: "solidusio/solidus", branch: branch
5
+ gem "solidus_auth_devise", github: "solidusio/solidus_auth_devise"
6
+
7
+ case ENV['DB']
8
+ when 'mysql'
9
+ gem 'mysql2'
10
+ when 'postgresql'
11
+ gem 'pg'
12
+ end
13
+
14
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2009-2014 Spree Commerce and contributors.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ * Neither the name Spree nor the names of its contributors may be used to
13
+ endorse or promote products derived from this software without specific
14
+ prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # Reviews
2
+
3
+ [![Build Status](https://travis-ci.org/solidusio-contrib/solidus_reviews.svg)](https://travis-ci.org/solidusio-contrib/solidus_reviews)
4
+
5
+ Straightforward review/rating functionality, updated for
6
+ [Solidus](https://solidus.io). While the Gem name has changed, the module
7
+ namespace and commands are still `spree` for now.
8
+
9
+ ---
10
+
11
+ ## Installation
12
+
13
+ Add the following to your `Gemfile` to install from git:
14
+
15
+ ```ruby
16
+ gem 'solidus_reviews', github: 'solidusio-contrib/solidus_reviews'
17
+ ```
18
+ Now bundle up with:
19
+
20
+ bundle
21
+
22
+ Next, run the rake task that copies the necessary migrations and assets to your project:
23
+
24
+ rails g solidus_reviews:install
25
+
26
+ And finish with a migrate:
27
+
28
+ rake db:migrate
29
+
30
+ Now you should be able to boot up your server with:
31
+
32
+ rails s
33
+
34
+ That's all!
35
+
36
+ ---
37
+
38
+ ## Usage
39
+
40
+ Action "submit" in "reviews" controller - goes to review entry form
41
+
42
+ Users must be logged in to submit a review
43
+
44
+ Three partials:
45
+ - `app/views/spree/products/_rating.html.erb` -- display number of stars
46
+ - `app/views/spree/products/_shortrating.html.erb` -- shorter version of above
47
+ - `app/views/spree/products/_review.html.erb` -- display a single review
48
+
49
+ Administrator can edit and/or approve and/or delete reviews.
50
+
51
+ ## Factories
52
+
53
+ If you want factories for our models available in your application, simply
54
+ require our factories in your `spec_helper.rb`:
55
+
56
+ ```ruby
57
+ require "solidus_reviews/factories"
58
+ ```
59
+
60
+ ## Implementation
61
+
62
+ Reviews table is quite obvious - and note the "approved" flag which is for the
63
+ administrator to update.
64
+
65
+ Ratings table holds current fractional value - avoids frequent recalc...
66
+
67
+ ---
68
+
69
+ ## Discussion
70
+
71
+ Some points which might need modification in future:
72
+
73
+ - I don't track the actual user on a review (just their "screen name" at the
74
+ time), but we may want to use this information to avoid duplicate reviews
75
+ etc. See https://github.com/spree/spree_reviews/issues/18
76
+ - Rating votes are tied to a review, to avoid spam. However: ratings are
77
+ accepted whether or not the review is accepted. Perhaps they should only
78
+ be counted when the review is approved.
79
+
80
+ ---
81
+
82
+ ## Contributing
83
+
84
+ See corresponding [contributing guidelines][1].
85
+
86
+ ---
87
+
88
+ Copyright (c) 2009-2014 [Spree Commerce][2] and [contributors][3], released under the [New BSD License][4]
89
+
90
+ [1]: ./CONTRIBUTING.md
91
+ [2]: https://github.com/spree
92
+ [3]: https://github.com/solidusio-contrib/solidus_reviews/graphs/contributors
93
+ [4]: ./LICENSE.md
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ require 'spree/testing_support/extension_rake'
6
+
7
+ RSpec::Core::RakeTask.new
8
+
9
+ task :default do
10
+ if Dir["spec/dummy"].empty?
11
+ Rake::Task[:test_app].invoke
12
+ Dir.chdir("../../")
13
+ end
14
+ Rake::Task[:spec].invoke
15
+ end
16
+
17
+ desc 'Generates a dummy app for testing'
18
+ task :test_app do
19
+ ENV['LIB_NAME'] = 'solidus_reviews'
20
+ Rake::Task['extension:test_app'].invoke
21
+ end
@@ -0,0 +1,7 @@
1
+ //= require jquery.rating
2
+ //= require spree/backend
3
+
4
+ // Navigating to a page with ratings via TurboLinks shows the radio buttons
5
+ $(document).on('page:load', function () {
6
+ $('input[type=radio].star').rating();
7
+ });
@@ -0,0 +1,7 @@
1
+ //= require jquery.rating
2
+ //= require spree/frontend
3
+
4
+ // Navigating to a page with ratings via TurboLinks shows the radio buttons
5
+ $(document).on('page:load', function () {
6
+ $('input[type=radio].star').rating();
7
+ });
@@ -0,0 +1,3 @@
1
+ /*
2
+ *= require spree/backend
3
+ */
@@ -0,0 +1,83 @@
1
+ /*
2
+ *= require spree/frontend
3
+ */
4
+
5
+ #reviews div.header {
6
+ margin-top: 10px;
7
+ margin-bottom: 10px;
8
+ }
9
+
10
+ .lit {
11
+ background-color: #aaaaaa;
12
+ color: #0000bb;
13
+ margin-right: 1px;
14
+ padding-left: 1px;
15
+ }
16
+
17
+ .unlit {
18
+ background-color: #aaaaaa;
19
+ color: #000000;
20
+ margin-right: 1px;
21
+ padding-left: 1px;
22
+ }
23
+
24
+ .star-rating-control {
25
+ display: inline-block;
26
+ height: 14px;
27
+ }
28
+
29
+ .review_hr {
30
+ size: 1px;
31
+ background: silver;
32
+ border: none;
33
+ margin: 1em 0;
34
+ }
35
+
36
+ /* jQuery.Rating Plugin CSS - http://www.fyneworks.com/jquery/star-rating/ */
37
+ div.rating-cancel, div.star-rating {
38
+ float: left;
39
+ width: 17px;
40
+ height: 16px;
41
+ text-indent: -999em;
42
+ cursor: pointer;
43
+ display: block;
44
+ background: transparent;
45
+ overflow: hidden
46
+ }
47
+
48
+ div.rating-cancel, div.rating-cancel a {
49
+ background: transparent image-url('store/reviews/delete.gif') no-repeat scroll 0 -1px;
50
+ }
51
+
52
+ div.star-rating, div.star-rating a {
53
+ background: image-url('store/reviews/star.gif') no-repeat 0 0px
54
+ }
55
+
56
+ div.rating-cancel a, div.star-rating a {
57
+ display: block;
58
+ width: 16px;
59
+ height: 100%;
60
+ background-position: 0 0px;
61
+ border: 0
62
+ }
63
+
64
+ div.star-rating-on a {
65
+ background-position: 0 -32px !important
66
+ }
67
+
68
+ div.star-rating-hover a {
69
+ background-position: 0 -32px
70
+ }
71
+
72
+ /* Read Only CSS */
73
+ div.star-rating-readonly a {
74
+ cursor: default !important
75
+ }
76
+
77
+ /* Partial Star CSS */
78
+ div.star-rating {
79
+ background: transparent !important;
80
+ overflow: hidden !important
81
+ }
82
+
83
+ /* END jQuery.Rating Plugin CSS */
@@ -0,0 +1,6 @@
1
+ class Spree::Admin::FeedbackReviewsController < Spree::Admin::ResourceController
2
+ belongs_to 'spree/review'
3
+ def index
4
+ @collection = parent.feedback_reviews
5
+ end
6
+ end
@@ -0,0 +1,21 @@
1
+ class Spree::Admin::ReviewSettingsController < Spree::Admin::BaseController
2
+ before_filter :process_unset_checkboxes, only: [:update]
3
+
4
+ def update
5
+ Spree::Reviews::Config.set(params[:preferences])
6
+
7
+ respond_to do |format|
8
+ format.html do
9
+ redirect_to edit_admin_review_settings_path
10
+ end
11
+ end
12
+ end
13
+
14
+ def process_unset_checkboxes
15
+ # workaround for unset checkbox behaviour
16
+ params[:preferences] ||= {}
17
+ Spree::ReviewsConfiguration.boolean_preferences.each do |sym|
18
+ params[:preferences][sym] = false if params[:preferences][sym].blank?
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,34 @@
1
+ class Spree::Admin::ReviewsController < Spree::Admin::ResourceController
2
+ helper Spree::ReviewsHelper
3
+
4
+ def index
5
+ @reviews = collection
6
+ end
7
+
8
+ def approve
9
+ r = Spree::Review.find(params[:id])
10
+
11
+ if r.update_attribute(:approved, true)
12
+ flash[:notice] = Spree.t("info_approve_review")
13
+ else
14
+ flash[:error] = Spree.t("error_approve_review")
15
+ end
16
+ redirect_to admin_reviews_path
17
+ end
18
+
19
+ def edit
20
+ if @review.product.nil?
21
+ flash[:error] = Spree.t("error_no_product")
22
+ redirect_to admin_reviews_path and return
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def collection
29
+ params[:q] ||= {}
30
+
31
+ @search = Spree::Review.ransack(params[:q])
32
+ @collection = @search.result.includes([:product, :user, :feedback_reviews]).page(params[:page]).per(params[:per_page])
33
+ end
34
+ end
@@ -0,0 +1,41 @@
1
+ class Spree::FeedbackReviewsController < Spree::StoreController
2
+ helper Spree::BaseHelper
3
+
4
+ before_filter :sanitize_rating, only: [:create]
5
+ before_filter :load_review, only: [:create]
6
+
7
+ def create
8
+
9
+ if @review.present?
10
+ @feedback_review = @review.feedback_reviews.new(feedback_review_params)
11
+ @feedback_review.user = spree_current_user
12
+ @feedback_review.locale = I18n.locale.to_s if Spree::Reviews::Config[:track_locale]
13
+ authorize! :create, @feedback_review
14
+ @feedback_review.save
15
+ end
16
+
17
+ respond_to do |format|
18
+ format.html { redirect_to :back }
19
+ format.js { render :action => :create }
20
+ end
21
+
22
+ end
23
+
24
+ protected
25
+ def load_review
26
+ @review ||= Spree::Review.find_by_id!(params[:review_id])
27
+ end
28
+
29
+ def permitted_feedback_review_attributes
30
+ [:rating, :comment]
31
+ end
32
+
33
+ def feedback_review_params
34
+ params.require(:feedback_review).permit(permitted_feedback_review_attributes)
35
+ end
36
+
37
+ def sanitize_rating
38
+ params[:feedback_review][:rating].to_s.sub!(/\s*[^0-9]*\z/,'') unless (params[:feedback_review] && params[:feedback_review][:rating].blank?)
39
+ end
40
+ end
41
+
@@ -0,0 +1,5 @@
1
+ Spree::ProductsController.class_eval do
2
+ helper Spree::ReviewsHelper
3
+
4
+ [:avg_rating, :reviews_count].each { |attrib| Spree::PermittedAttributes.product_attributes << attrib }
5
+ end
@@ -0,0 +1,48 @@
1
+ class Spree::ReviewsController < Spree::StoreController
2
+ helper Spree::BaseHelper
3
+ before_filter :load_product, :only => [:index, :new, :create]
4
+ rescue_from ActiveRecord::RecordNotFound, :with => :render_404
5
+
6
+ def index
7
+ @approved_reviews = Spree::Review.approved.where(product: @product)
8
+ end
9
+
10
+ def new
11
+ @review = Spree::Review.new(:product => @product)
12
+ authorize! :create, @review
13
+ end
14
+
15
+ # save if all ok
16
+ def create
17
+ params[:review][:rating].sub!(/\s*[^0-9]*\z/,'') unless params[:review][:rating].blank?
18
+
19
+ @review = Spree::Review.new(review_params)
20
+ @review.product = @product
21
+ @review.user = spree_current_user if spree_user_signed_in?
22
+ @review.ip_address = request.remote_ip
23
+ @review.locale = I18n.locale.to_s if Spree::Reviews::Config[:track_locale]
24
+
25
+ authorize! :create, @review
26
+ if @review.save
27
+ flash[:notice] = Spree.t('review_successfully_submitted')
28
+ redirect_to spree.product_path(@product)
29
+ else
30
+ render :new
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def load_product
37
+ @product = Spree::Product.friendly.find(params[:product_id])
38
+ end
39
+
40
+ def permitted_review_attributes
41
+ [:rating, :title, :review, :name, :show_identifier]
42
+ end
43
+
44
+ def review_params
45
+ params.require(:review).permit(permitted_review_attributes)
46
+ end
47
+
48
+ end
@@ -0,0 +1,17 @@
1
+ module Spree::ReviewsHelper
2
+
3
+ def star(the_class)
4
+ content_tag(:span, " &#10030; ".html_safe, :class => the_class)
5
+ end
6
+
7
+ def mk_stars(m)
8
+ (1..5).collect {|n| n <= m ? star("lit") : star("unlit") }.join
9
+ end
10
+
11
+ def txt_stars(n, show_out_of = true)
12
+ res = Spree.t('star', :count => n)
13
+ res += " #{Spree.t('out_of_5')}" if show_out_of
14
+ res
15
+ end
16
+
17
+ end
@@ -0,0 +1,17 @@
1
+ class Spree::FeedbackReview < ActiveRecord::Base
2
+ belongs_to :user, :class_name => Spree.user_class.to_s
3
+
4
+ belongs_to :review, dependent: :destroy
5
+ validates :review, presence: true
6
+
7
+ validates :rating, numericality: { only_integer: true,
8
+ greater_than_or_equal_to: 1,
9
+ less_than_or_equal_to: 5,
10
+ message: Spree.t('you_must_enter_value_for_rating') }
11
+
12
+ scope :most_recent_first, -> { order("spree_feedback_reviews.created_at DESC") }
13
+ default_scope { most_recent_first }
14
+
15
+ scope :localized, lambda { |lc| where('spree_feedback_reviews.locale = ?', lc) }
16
+
17
+ end
@@ -0,0 +1,21 @@
1
+ # Add access to reviews/ratings to the product model
2
+ Spree::Product.class_eval do
3
+ has_many :reviews
4
+
5
+ def stars
6
+ avg_rating.try(:round) || 0
7
+ end
8
+
9
+ def recalculate_rating
10
+ reviews_count = self.reviews.reload.approved.count
11
+
12
+ self.reviews_count = reviews_count
13
+ if reviews_count > 0
14
+ self.avg_rating = self.reviews.approved.sum(:rating).to_f / reviews_count
15
+ else
16
+ self.avg_rating = 0
17
+ end
18
+ self.save
19
+ end
20
+
21
+ end
@@ -0,0 +1,36 @@
1
+ class Spree::Review < ActiveRecord::Base
2
+ belongs_to :product, touch: true
3
+ belongs_to :user, :class_name => Spree.user_class.to_s
4
+ has_many :feedback_reviews
5
+
6
+ after_save :recalculate_product_rating, :if => :approved?
7
+ after_destroy :recalculate_product_rating
8
+
9
+ validates :name, presence: true
10
+ validates :review, presence: true
11
+
12
+ validates :rating, numericality: { only_integer: true,
13
+ greater_than_or_equal_to: 1,
14
+ less_than_or_equal_to: 5,
15
+ message: Spree.t('you_must_enter_value_for_rating') }
16
+
17
+
18
+ default_scope { order("spree_reviews.created_at DESC") }
19
+
20
+ scope :localized, ->(lc) { where('spree_reviews.locale = ?', lc) }
21
+ scope :most_recent_first, -> { order('spree_reviews.created_at DESC') }
22
+ scope :oldest_first, -> { reorder('spree_reviews.created_at ASC') }
23
+ scope :preview, -> { limit(Spree::Reviews::Config[:preview_size]).oldest_first }
24
+ scope :approved, -> { where(approved: true) }
25
+ scope :not_approved, -> { where(approved: false) }
26
+ scope :default_approval_filter, -> { Spree::Reviews::Config[:include_unapproved_reviews] ? all : approved }
27
+
28
+ def feedback_stars
29
+ return 0 if feedback_reviews.size <= 0
30
+ ((feedback_reviews.sum(:rating) / feedback_reviews.size) + 0.5).floor
31
+ end
32
+
33
+ def recalculate_product_rating
34
+ self.product.recalculate_rating if product.present?
35
+ end
36
+ end
@@ -0,0 +1,17 @@
1
+ class Spree::ReviewsAbility
2
+ include CanCan::Ability
3
+
4
+ def initialize user
5
+ review_ability_class = self.class
6
+ can :create, Spree::Review do |review|
7
+ review_ability_class.allow_anonymous_reviews? || !user.email.blank?
8
+ end
9
+ can :create, Spree::FeedbackReview do |review|
10
+ review_ability_class.allow_anonymous_reviews? || !user.email.blank?
11
+ end
12
+ end
13
+
14
+ def self.allow_anonymous_reviews?
15
+ !Spree::Reviews::Config[:require_login]
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ class Spree::ReviewsConfiguration < Spree::Preferences::Configuration
2
+ def self.boolean_preferences
3
+ %w(include_unapproved_reviews feedback_rating show_email require_login track_locale)
4
+ end
5
+
6
+ # include non-approved reviews in (public) listings
7
+ preference :include_unapproved_reviews, :boolean, :default => false
8
+
9
+ # control how many reviews are shown in summaries etc.
10
+ preference :preview_size, :integer, :default => 3
11
+
12
+ # show a reviewer's email address
13
+ preference :show_email, :boolean, :default => false
14
+
15
+ # show helpfullness rating form elements
16
+ preference :feedback_rating, :boolean, :default => false
17
+
18
+ # require login to post reviews
19
+ preference :require_login, :boolean, :default => true
20
+
21
+ # whether to keep track of the reviewer's locale
22
+ preference :track_locale, :boolean, :default => false
23
+
24
+ # render checkbox for a user to approve to show their identifier (name or email) on their review
25
+ preference :render_show_identifier_checkbox, :boolean, :default => false
26
+ end
@@ -0,0 +1,5 @@
1
+ Deface::Override.new(:virtual_path => "spree/products/show",
2
+ :name => "converted_product_properties_767643482",
3
+ :insert_after => "[data-hook='product_properties']",
4
+ :partial => "spree/shared/reviews",
5
+ :disabled => false)
@@ -0,0 +1,4 @@
1
+ Deface::Override.new(:virtual_path => "spree/admin/shared/_product_sub_menu",
2
+ :name => "reviews_admin_tab",
3
+ :insert_bottom => "[data-hook='admin_product_sub_tabs']",
4
+ :text => "<%= tab(:reviews, :label => 'review_management') %>")
@@ -0,0 +1,5 @@
1
+ Deface::Override.new(:virtual_path => "spree/admin/shared/_configuration_menu",
2
+ :name => "converted_admin_configurations_menu",
3
+ :insert_bottom => "[data-hook='admin_configurations_sidebar_menu'], #admin_configurations_sidebar_menu[data-hook]",
4
+ :text => "<%= configurations_sidebar_menu_item Spree.t('spree_reviews.review_settings'), edit_admin_review_settings_path %>",
5
+ :disabled => false)