solidus_reviews 1.3.0 → 1.4.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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/.gem_release.yml +5 -0
  3. data/.github/stale.yml +17 -0
  4. data/.gitignore +11 -8
  5. data/.rspec +1 -1
  6. data/.rubocop.yml +1 -11
  7. data/CHANGELOG.md +32 -0
  8. data/Gemfile +9 -13
  9. data/{LICENSE.md → LICENSE} +1 -1
  10. data/Rakefile +4 -19
  11. data/app/controllers/spree/reviews_controller.rb +29 -2
  12. data/app/decorators/controllers/solidus_reviews/spree/{admin/products_controller_decorator.rb → products_controller_decorator.rb} +0 -4
  13. data/app/models/spree/feedback_review.rb +1 -1
  14. data/app/models/spree/permission_sets/review_display.rb +11 -0
  15. data/app/models/spree/permission_sets/review_management.rb +11 -0
  16. data/app/models/spree/review.rb +16 -2
  17. data/app/models/spree/reviews_ability.rb +5 -0
  18. data/app/models/spree/reviews_configuration.rb +10 -1
  19. data/app/overrides/add_reviews_tab_to_admin.rb +12 -4
  20. data/app/overrides/add_reviews_to_admin_configuration_sidebar.rb +12 -5
  21. data/app/views/spree/admin/review_settings/edit.html.erb +7 -0
  22. data/app/views/spree/admin/reviews/edit.html.erb +4 -2
  23. data/app/views/spree/admin/reviews/index.html.erb +9 -5
  24. data/app/views/spree/reviews/_form.html.erb +6 -4
  25. data/app/views/spree/reviews/edit.html.erb +3 -0
  26. data/app/views/spree/shared/_review.html.erb +6 -4
  27. data/bin/console +17 -0
  28. data/bin/rails +11 -3
  29. data/bin/setup +8 -0
  30. data/config/locales/de-CH.yml +1 -1
  31. data/config/locales/de.yml +1 -1
  32. data/config/locales/en-GB.yml +2 -1
  33. data/config/locales/en.yml +2 -1
  34. data/config/locales/es.yml +2 -1
  35. data/config/locales/fr.yml +1 -1
  36. data/config/locales/it.yml +1 -1
  37. data/config/locales/pl.yml +1 -1
  38. data/config/locales/pt-BR.yml +1 -1
  39. data/config/locales/pt.yml +1 -1
  40. data/config/locales/ro.yml +1 -1
  41. data/config/locales/sv.yml +1 -1
  42. data/config/locales/tr.yml +1 -1
  43. data/config/locales/uk.yml +1 -1
  44. data/config/locales/zh-CN.yml +1 -1
  45. data/config/locales/zh-TW.yml +1 -1
  46. data/config/routes.rb +3 -1
  47. data/lib/controllers/spree/api/feedback_reviews_controller.rb +91 -0
  48. data/lib/solidus_reviews.rb +2 -4
  49. data/lib/solidus_reviews/engine.rb +12 -8
  50. data/lib/solidus_reviews/version.rb +1 -1
  51. data/solidus_reviews.gemspec +19 -12
  52. data/spec/controllers/spree/api/feedback_reviews_controller_spec.rb +136 -0
  53. data/spec/controllers/spree/reviews_controller_spec.rb +136 -0
  54. data/spec/models/review_spec.rb +27 -0
  55. data/spec/models/reviews_configuration_spec.rb +12 -0
  56. data/spec/spec_helper.rb +16 -3
  57. metadata +48 -39
  58. data/spec/controllers/spree/products_controller_spec.rb +0 -11
@@ -21,10 +21,12 @@
21
21
  <%= f.text_area :review, wrap: "virtual", rows: "10", cols: "50" %>
22
22
  </p>
23
23
 
24
- <p class="review_images_field">
25
- <%= f.label :images %><br>
26
- <%= f.file_field :images, :accept => "image/*", multiple: true %>
27
- </p>
24
+ <% if Spree::Reviews::Config[:allow_image_upload] %>
25
+ <p class="review_images_field">
26
+ <%= f.label :images %><br>
27
+ <%= f.file_field :images, :accept => "image/*", multiple: true %>
28
+ </p>
29
+ <% end %>
28
30
 
29
31
  <% if Spree::Reviews::Config[:render_show_identifier_checkbox] %>
30
32
  <p class="review_show_identifier_field">
@@ -0,0 +1,3 @@
1
+ <%= content_tag :h2, I18n.t("spree.leave_us_a_review_for", name: @product.name), class: 'new-review-title' %>
2
+
3
+ <%= render 'form', review: @review, product: @product %>
@@ -24,10 +24,12 @@
24
24
  <div itemprop="reviewBody">
25
25
  <%= simple_format(review.review) %>
26
26
  </div>
27
- <% review.images.each do |image| %>
28
- <div itemprop="image">
29
- <%= link_to image_tag(image.url(:product)), image.url(:original) %>
30
- </div>
27
+ <% if Spree::Reviews::Config[:allow_image_upload] %>
28
+ <% review.images.each do |image| %>
29
+ <div itemprop="image">
30
+ <%= link_to image_tag(image.url(:product)), image.url(:original) %>
31
+ </div>
32
+ <% end %>
31
33
  <% end %>
32
34
  <% if Spree::Reviews::Config[:feedback_rating] && (!Spree::Reviews::Config[:require_login] || spree_current_user) %>
33
35
  <div class="feedback_review" id="feedback_review_<%= review.id %>">
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require "bundler/setup"
6
+ require "solidus_reviews"
7
+
8
+ # You can add fixtures and/or initialization code here to make experimenting
9
+ # with your gem easier. You can also use a different console, if you like.
10
+ $LOAD_PATH.unshift(*Dir["#{__dir__}/../app/*"])
11
+
12
+ # (If you use this, don't forget to add pry to your Gemfile!)
13
+ # require "pry"
14
+ # Pry.start
15
+
16
+ require "irb"
17
+ IRB.start(__FILE__)
data/bin/rails CHANGED
@@ -1,7 +1,15 @@
1
1
  #!/usr/bin/env ruby
2
+
2
3
  # frozen_string_literal: true
3
4
 
4
- # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
5
+ app_root = 'spec/dummy'
6
+
7
+ unless File.exist? "#{app_root}/bin/rails"
8
+ system "bin/rake", app_root or begin # rubocop:disable Style/AndOr
9
+ warn "Automatic creation of the dummy app failed"
10
+ exit 1
11
+ end
12
+ end
5
13
 
6
- ENGINE_PATH = File.expand_path('..', __dir__)
7
- load File.expand_path('../spec/dummy/script/rails', __dir__)
14
+ Dir.chdir app_root
15
+ exec 'bin/rails', *ARGV
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ gem install bundler --conservative
7
+ bundle update
8
+ bundle exec rake extension:test_app
@@ -36,7 +36,7 @@ de-CH:
36
36
  one: basiert auf einer Rezension
37
37
  other: "basiert auf %{count} Rezensionen"
38
38
  by: Von
39
- editing_review_for_html: 'Rezension über %{link} bearbeiten'
39
+ editing_review_for_html: 'Rezension über %{product_name} bearbeiten'
40
40
  error_approve_review: Fehler bei der Freischaltung
41
41
  error_no_product: Das rezensierte Produkt existiert nicht mehr.
42
42
  feedback: Feedback
@@ -36,7 +36,7 @@ de:
36
36
  one: basiert auf einer Rezension
37
37
  other: "basiert auf %{count} Rezensionen"
38
38
  by: Von
39
- editing_review_for_html: 'Rezension über %{link} bearbeiten'
39
+ editing_review_for_html: 'Rezension über %{product_name} bearbeiten'
40
40
  error_approve_review: Fehler bei der Freischaltung
41
41
  error_no_product: Das rezensierte Produkt existiert nicht mehr.
42
42
  feedback: Feedback
@@ -35,7 +35,7 @@ en-GB:
35
35
  one: based upon one review
36
36
  other: "based upon %{count} reviews"
37
37
  by: by
38
- editing_review_for_html: 'Editing review for %{link}'
38
+ editing_review_for_html: 'Editing review for %{product_name}'
39
39
  error_approve_review: Error approving review
40
40
  error_no_product: The reviewed product doesn't exist anymore
41
41
  feedback: Feedback
@@ -64,6 +64,7 @@ en-GB:
64
64
  show_email: Show email addresses
65
65
  show_verified_purchaser: Show verified purchaser
66
66
  track_locale: Track user's locale
67
+ allow_image_upload: Allow images to be attached to reviews
67
68
  star:
68
69
  one: "1"
69
70
  other: "%{count}"
@@ -35,7 +35,7 @@ en:
35
35
  one: based upon one review
36
36
  other: "based upon %{count} reviews"
37
37
  by: by
38
- editing_review_for_html: 'Editing review for %{link}'
38
+ editing_review_for_html: 'Editing review for %{product_name}'
39
39
  error_approve_review: Error approving review
40
40
  error_no_product: The reviewed product doesn't exist anymore
41
41
  feedback: Feedback
@@ -64,6 +64,7 @@ en:
64
64
  show_email: Show email addresses
65
65
  show_verified_purchaser: Show verified purchaser
66
66
  track_locale: Track user's locale
67
+ allow_image_upload: Allow images to be attached to reviews
67
68
  star:
68
69
  one: "1"
69
70
  other: "%{count}"
@@ -35,7 +35,7 @@ es:
35
35
  one: "basado en una valoración"
36
36
  other: "basado en %{count} valoraciones"
37
37
  by: por
38
- editing_review_for_html: 'Editando la valoración para %{link}'
38
+ editing_review_for_html: 'Editando la valoración para %{product_name}'
39
39
  error_approve_review: "Error aprobando la valoración"
40
40
  error_no_product: "El producto valorado ya no existe"
41
41
  feedback: Feedback
@@ -64,6 +64,7 @@ es:
64
64
  show_email: "Mostrar las direcciones de correo"
65
65
  show_verified_purchaser: Mostrar comprador verificado
66
66
  track_locale: "Rastrear el locale del usuario"
67
+ allow_image_upload: "Permitir adjuntar imagenes con el comentario"
67
68
  star:
68
69
  one: "1"
69
70
  other: "%{count}"
@@ -35,7 +35,7 @@ fr:
35
35
  one: basé sur un commentaire
36
36
  other: "basé sur %{count} commentaires"
37
37
  by: par
38
- editing_review_for_html: 'Modification du commentaire pour %{link}'
38
+ editing_review_for_html: 'Modification du commentaire pour %{product_name}'
39
39
  error_approve_review: Erreur en approuvant le commentaire
40
40
  error_no_product: Le produit commenté n'existe plus
41
41
  feedback: Réaction
@@ -34,7 +34,7 @@ it:
34
34
  one: basato su una recensione
35
35
  other: "basato su %{count} recensioni"
36
36
  by: da
37
- editing_review_for_html: 'Modifica la recensione per %{link}'
37
+ editing_review_for_html: 'Modifica la recensione per %{product_name}'
38
38
  error_approve_review: Errore approvazione recensione
39
39
  error_no_product: "Il prodotto recensito non esiste più"
40
40
  feedback: Feedback
@@ -37,7 +37,7 @@ pl:
37
37
  few: "na podstawie %{count} opinii"
38
38
  other: "na podstawie %{count} opinii"
39
39
  by: "przez"
40
- editing_review_for_html: 'Edycja opinii dla %{link}'
40
+ editing_review_for_html: 'Edycja opinii dla %{product_name}'
41
41
  error_approve_review: Błąd przy zatwierdzaniu opinii
42
42
  error_no_product: Oceniamy produkt nie istnieje
43
43
  feedback: Komentarz
@@ -35,7 +35,7 @@ pt-BR:
35
35
  one: 'baseado em uma avaliação'
36
36
  other: "baseado em %{count} avaliações"
37
37
  by: 'por'
38
- editing_review_for_html: 'Editando avaliação para %{link}'
38
+ editing_review_for_html: 'Editando avaliação para %{product_name}'
39
39
  error_approve_review: 'Erro aprovando avaliação'
40
40
  error_no_product: "O produto avaliado não existe mais"
41
41
  feedback: 'Parecer'
@@ -35,7 +35,7 @@ pt:
35
35
  one: baseada numa avaliação
36
36
  other: "baseada em %{count} avaliações"
37
37
  by: por
38
- editing_review_for_html: 'Editando a avaliação para %{link}'
38
+ editing_review_for_html: 'Editando a avaliação para %{product_name}'
39
39
  error_approve_review: Erro aprovando a avaliação
40
40
  error_no_product: O produto avaliado já não existe
41
41
  feedback: Feedback
@@ -39,7 +39,7 @@ ro:
39
39
  other: "bazată pe %{count} recenzii"
40
40
  many: "bazată pe %{count} de recenzii"
41
41
  by: de
42
- editing_review_for_html: 'Editare recenzie pentru %{link}'
42
+ editing_review_for_html: 'Editare recenzie pentru %{product_name}'
43
43
  error_approve_review: Eroare la aprobarea recenziei
44
44
  error_no_product: Produsul recenziat nu mai există
45
45
  feedback: Feedback
@@ -35,7 +35,7 @@ sv:
35
35
  one: "baserad på en recension"
36
36
  other: "baserad på %{count} recensioner"
37
37
  by: av
38
- editing_review_for_html: "Editerad recension för %{link}"
38
+ editing_review_for_html: "Editerad recension för %{product_name}"
39
39
  error_approve_review: "Problem med att godkänna recension"
40
40
  error_no_product: "Den betygsatta produkten finns inte längre"
41
41
  feedback: Återkoppling
@@ -35,7 +35,7 @@ tr:
35
35
  one: bir incelemeye göre
36
36
  other: "%{count} incelemeye göre"
37
37
  by: tarafından
38
- editing_review_for_html: 'Yorumu düzenle %{link}'
38
+ editing_review_for_html: 'Yorumu düzenle %{product_name}'
39
39
  error_approve_review: Yorum onaylamada hata
40
40
  error_no_product: Yorumlanan ürün artık yok
41
41
  feedback: Geri bildirim
@@ -39,7 +39,7 @@ uk:
39
39
  many: "на основі %{count} відгуків"
40
40
  other: "на основі %{count} відгуків"
41
41
  by: від
42
- editing_review_for_html: 'Редагувати відгук на %{link}'
42
+ editing_review_for_html: 'Редагувати відгук на %{product_name}'
43
43
  error_approve_review: Не вдалось схвалити відгук
44
44
  error_no_product: Товару, на який писався відгук, більше не існує
45
45
  feedback: Корисність
@@ -33,7 +33,7 @@ zh-CN:
33
33
  one: 以评论为基础
34
34
  other: "以 %{count} 個评论为基础"
35
35
  by: 由
36
- editing_review_for_html: '正在修改 %{link} 的评论'
36
+ editing_review_for_html: '正在修改 %{product_name} 的评论'
37
37
  error_approve_review: 出错了,不能核准评论
38
38
  error_no_product: 被评论的产品不存在了。
39
39
  feedback: 回馈
@@ -33,7 +33,7 @@ zh-TW:
33
33
  one: 以評論為基礎
34
34
  other: '以 %{count} 個評論為基礎'
35
35
  by: 由
36
- editing_review_for_html: '正在修改 %{link} 的評論'
36
+ editing_review_for_html: '正在修改 %{product_name} 的評論'
37
37
  error_approve_review: 出錯了,不能核準評論
38
38
  error_no_product: 被評論的產品不存在了。
39
39
  feedback: 回饋
@@ -13,7 +13,7 @@ Spree::Core::Engine.routes.draw do
13
13
  end
14
14
 
15
15
  resources :products, only: [] do
16
- resources :reviews, only: [:index, :new, :create] do
16
+ resources :reviews, only: [:index, :new, :create, :edit, :update] do
17
17
  end
18
18
  end
19
19
  post '/reviews/:review_id/feedback(.:format)' => 'feedback_reviews#create', as: :feedback_reviews
@@ -22,6 +22,8 @@ Spree::Core::Engine.routes.draw do
22
22
  namespace :api, defaults: { format: 'json' } do
23
23
  resources :reviews, only: [:show, :create, :update, :destroy]
24
24
 
25
+ resources :feedback_reviews, only: [:create, :update, :destroy]
26
+
25
27
  resources :products do
26
28
  resources :reviews, only: [:index]
27
29
  end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Api
5
+ class FeedbackReviewsController < Spree::Api::BaseController
6
+ respond_to :json
7
+
8
+ before_action :load_review, only: [:create, :update, :destroy]
9
+ before_action :load_feedback_review, only: [:update, :destroy]
10
+ before_action :find_review_user
11
+ before_action :sanitize_rating, only: [:create, :update]
12
+ before_action :prevent_multiple_feedback_reviews, only: [:create]
13
+
14
+ def create
15
+ if @review.present?
16
+ @feedback_review = @review.feedback_reviews.new(feedback_review_params)
17
+ @feedback_review.user = @current_api_user
18
+ @feedback_review.locale = I18n.locale.to_s if Spree::Reviews::Config[:track_locale]
19
+ end
20
+
21
+ authorize! :create, @feedback_review
22
+ if @feedback_review.save
23
+ render json: @feedback_review, status: :created
24
+ else
25
+ invalid_resource!(@feedback_review)
26
+ end
27
+ end
28
+
29
+ def update
30
+ authorize! :update, @feedback_review
31
+
32
+ if @feedback_review.update(feedback_review_params)
33
+ render json: @feedback_review, status: :ok
34
+ else
35
+ invalid_resource!(@feedback_review)
36
+ end
37
+ end
38
+
39
+ def destroy
40
+ authorize! :destroy, @feedback_review
41
+
42
+ if @feedback_review.destroy
43
+ render json: @feedback_review, status: :ok
44
+ else
45
+ invalid_resource!(@feedback_review)
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def permitted_feedback_review_attributes
52
+ [:rating, :comment]
53
+ end
54
+
55
+ def feedback_review_params
56
+ params.require(:feedback_review).permit(permitted_feedback_review_attributes)
57
+ end
58
+
59
+ # Finds user based on api_key or by user_id if api_key belongs to an admin.
60
+ def find_review_user
61
+ if params[:user_id] && @current_user_roles.include?('admin')
62
+ @current_api_user = Spree.user_class.find(params[:user_id])
63
+ end
64
+ end
65
+
66
+ # Loads any review that is shared between the user and product
67
+ def load_review
68
+ @review = Spree::Review.find(params[:review_id])
69
+ end
70
+
71
+ # Loads the feedback_review
72
+ def load_feedback_review
73
+ @feedback_review = Spree::FeedbackReview.find(params[:id])
74
+ end
75
+
76
+ # Ensures that a user can't leave multiple feedbacks on a single review
77
+ def prevent_multiple_feedback_reviews
78
+ @feedback_review = @review.feedback_reviews.find_by(user_id: @current_api_user)
79
+ if @feedback_review.present?
80
+ invalid_resource!(@feedback_review)
81
+ end
82
+ end
83
+
84
+ # Converts rating strings like "5 units" to "5"
85
+ # Operates on params
86
+ def sanitize_rating
87
+ params[:rating].to_s.sub!(/\s*[^0-9]*\z/, '') unless params[:feedback_review] && params[:feedback_review][:rating].blank?
88
+ end
89
+ end
90
+ end
91
+ end
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'solidus'
3
+ require 'solidus_core'
4
4
  require 'solidus_support'
5
- require 'sassc/rails'
6
5
  require 'deface'
7
- require 'coffee_script'
8
6
 
9
- require 'solidus_reviews/engine'
10
7
  require 'solidus_reviews/version'
8
+ require 'solidus_reviews/engine'
@@ -1,22 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'spree/core'
4
+
3
5
  module SolidusReviews
4
6
  class Engine < Rails::Engine
5
- require 'spree/core'
6
- isolate_namespace ::Spree
7
+ include SolidusSupport::EngineExtensions
8
+
9
+ isolate_namespace Spree
10
+
7
11
  engine_name 'solidus_reviews'
8
12
 
9
- def self.activate
10
- Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c|
11
- Rails.configuration.cache_classes ? require(c) : load(c)
12
- end
13
+ # use rspec for tests
14
+ config.generators do |g|
15
+ g.test_framework :rspec
16
+ end
17
+
18
+ config.to_prepare do
13
19
  ::Spree::Ability.register_ability(::Spree::ReviewsAbility)
14
20
  end
15
21
 
16
22
  if SolidusSupport.api_available?
17
23
  paths["app/controllers"] << "lib/controllers"
18
24
  end
19
-
20
- config.to_prepare &method(:activate).to_proc
21
25
  end
22
26
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusReviews
4
- VERSION = '1.3.0'
4
+ VERSION = '1.4.0'
5
5
  end
@@ -4,25 +4,32 @@ $:.push File.expand_path('lib', __dir__)
4
4
  require 'solidus_reviews/version'
5
5
 
6
6
  Gem::Specification.new do |s|
7
- s.platform = Gem::Platform::RUBY
8
7
  s.name = 'solidus_reviews'
9
8
  s.version = SolidusReviews::VERSION
10
9
  s.summary = 'Review and rating functionality for your Solidus store.'
11
- s.authors = ['Solidus Contrib']
12
- s.description = s.summary
13
- s.required_ruby_version = '>= 1.9.3'
10
+ s.license = 'BSD-3-Clause'
14
11
 
12
+ s.author = 'Solidus Contrib'
15
13
  s.homepage = 'https://github.com/solidusio-contrib/solidus_reviews'
16
- s.license = 'BSD-3'
17
14
 
18
- s.files = `git ls-files`.split("\n")
19
- s.test_files = `git ls-files -- spec/*`.split("\n")
20
- s.require_path = 'lib'
21
- s.requirements << 'none'
15
+ if s.respond_to?(:metadata)
16
+ s.metadata["homepage_uri"] = s.homepage if s.homepage
17
+ s.metadata["source_code_uri"] = s.homepage if s.homepage
18
+ end
19
+
20
+ s.required_ruby_version = '~> 2.4'
21
+
22
+ s.files = Dir.chdir(File.expand_path(__dir__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ end
25
+ s.test_files = Dir['spec/**/*']
26
+ s.bindir = "exe"
27
+ s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ s.require_paths = ["lib"]
22
29
 
23
30
  s.add_dependency 'deface', '~> 1.0'
24
- s.add_dependency 'solidus', ['>= 1.4', '< 3']
25
- s.add_dependency 'solidus_support'
31
+ s.add_dependency 'solidus_core', ['>= 2.0.0', '< 3']
32
+ s.add_dependency 'solidus_support', '~> 0.4'
26
33
 
27
- s.add_development_dependency 'solidus_extension_dev_tools'
34
+ s.add_development_dependency 'solidus_dev_support'
28
35
  end