solidus_reviews 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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)