├── .rspec ├── .rubocop.yml ├── lib ├── acts_as_commentable.rb ├── solidus_comments │ ├── version.rb │ ├── testing_support │ │ └── factories.rb │ └── engine.rb ├── solidus_comments.rb ├── acts_as_commentable │ ├── commentable_methods.rb │ └── MIT-LICENSE └── generators │ └── solidus_comments │ └── install │ └── install_generator.rb ├── .gem_release.yml ├── bin ├── setup ├── rails └── console ├── app ├── views │ └── spree │ │ └── admin │ │ ├── orders │ │ └── comments.html.erb │ │ ├── shipments │ │ └── comments.html.erb │ │ ├── comment_types │ │ ├── edit.html.erb │ │ ├── new.html.erb │ │ ├── _form.html.erb │ │ └── index.html.erb │ │ └── shared │ │ ├── _comment_list.html.erb │ │ └── _comments.html.erb ├── models │ └── spree │ │ ├── comment_type.rb │ │ └── comment.rb ├── controllers │ └── spree │ │ └── admin │ │ ├── comment_types_controller.rb │ │ └── comments_controller.rb ├── overrides │ └── spree │ │ └── admin │ │ └── shared │ │ ├── _configuration_menu │ │ └── add_comment_configuration.html.erb.deface │ │ └── _order_submenu │ │ └── add_comment_to_admin_orders_tabs.html.erb.deface └── decorators │ ├── models │ └── solidus_comments │ │ └── spree │ │ ├── order_decorator.rb │ │ └── shipment_decorator.rb │ └── controllers │ └── solidus_comments │ └── spree │ └── admin │ └── orders_controller_decorator.rb ├── Rakefile ├── .gitignore ├── spec ├── support │ ├── shoulda.rb │ └── feature_helper.rb ├── model │ ├── comment_spec.rb │ └── spree │ │ ├── order_spec.rb │ │ ├── shipment_spec.rb │ │ └── comment_spec.rb ├── features │ └── admin │ │ ├── comment_types_spec.rb │ │ └── order_comments_spec.rb └── spec_helper.rb ├── db └── migrate │ ├── 20111123200847_prefix_tables_with_spree.rb │ ├── 20100406100728_add_type_to_comments.rb │ ├── 20100406085611_create_comment_types.rb │ └── 20091021182639_create_comments.rb ├── config ├── routes.rb └── locales │ ├── ru.yml │ └── en.yml ├── .github └── stale.yml ├── Gemfile ├── README.md ├── .circleci └── config.yml ├── solidus_comments.gemspec └── LICENSE /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | require: 2 | - solidus_dev_support/rubocop 3 | -------------------------------------------------------------------------------- /lib/acts_as_commentable.rb: -------------------------------------------------------------------------------- 1 | require "acts_as_commentable/commentable_methods" 2 | -------------------------------------------------------------------------------- /lib/solidus_comments/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SolidusComments 4 | VERSION = '1.0.1' 5 | end 6 | -------------------------------------------------------------------------------- /.gem_release.yml: -------------------------------------------------------------------------------- 1 | bump: 2 | recurse: false 3 | file: 'lib/solidus_comments/version.rb' 4 | message: Bump SolidusComments to %{version} 5 | tag: true 6 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 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 9 | -------------------------------------------------------------------------------- /app/views/spree/admin/orders/comments.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'spree/admin/shared/order_tabs', :current => 'Comments' %> 2 | <%= render 'spree/admin/shared/comments', :commentable => @order %> 3 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'solidus_dev_support/rake_tasks' 4 | SolidusDevSupport::RakeTasks.install 5 | 6 | task default: %w[extension:test_app extension:specs] 7 | -------------------------------------------------------------------------------- /app/models/spree/comment_type.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Spree 4 | class CommentType < ApplicationRecord 5 | ORDER = "Order" 6 | 7 | has_many :comments 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | \#* 3 | *~ 4 | .#* 5 | .DS_Store 6 | .idea 7 | .project 8 | .sass-cache 9 | coverage 10 | Gemfile.lock 11 | tmp 12 | nbproject 13 | pkg 14 | *.swp 15 | spec/dummy 16 | spec/examples.txt 17 | -------------------------------------------------------------------------------- /app/controllers/spree/admin/comment_types_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Spree 4 | module Admin 5 | class CommentTypesController < Spree::Admin::ResourceController 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/support/shoulda.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'shoulda-matchers' 4 | 5 | Shoulda::Matchers.configure do |config| 6 | config.integrate do |with| 7 | with.test_framework :rspec 8 | with.library :rails 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/solidus_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'solidus_core' 4 | require 'solidus_support' 5 | 6 | require 'deface' 7 | require 'acts_as_commentable' 8 | 9 | require 'solidus_comments/version' 10 | require 'solidus_comments/engine' 11 | -------------------------------------------------------------------------------- /app/overrides/spree/admin/shared/_configuration_menu/add_comment_configuration.html.erb.deface: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= configurations_sidebar_menu_item I18n.t("spree.comment_types"), 4 | admin_comment_types_path %> 5 | -------------------------------------------------------------------------------- /db/migrate/20111123200847_prefix_tables_with_spree.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class PrefixTablesWithSpree < SolidusSupport::Migration[4.2] 4 | def change 5 | rename_table :comments, :spree_comments 6 | rename_table :comment_types, :spree_comment_types 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/solidus_comments/testing_support/factories.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :comment, class: Spree::Comment do 5 | association :commentable, factory: :order 6 | user 7 | sequence(:comment) { |n| "Comment #{n}" } 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20100406100728_add_type_to_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddTypeToComments < SolidusSupport::Migration[4.2] 4 | def self.up 5 | add_column :comments, :comment_type_id, :integer 6 | end 7 | 8 | def self.down 9 | remove_column :comments, :comment_type_id 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/decorators/models/solidus_comments/spree/order_decorator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SolidusComments 4 | module Spree 5 | module OrderDecorator 6 | def self.prepended(base) 7 | base.acts_as_commentable 8 | end 9 | 10 | ::Spree::Order.prepend self 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Spree::Core::Engine.routes.draw do 4 | namespace :admin do 5 | resources :comments, only: [:create, :update, :destroy] 6 | resources :comment_types 7 | 8 | resources :orders do 9 | member do 10 | get :comments 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/model/comment_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.describe Spree::Comment, type: :model do 4 | it 'has a valid factory' do 5 | expect(build_stubbed(:comment)).to be_valid 6 | end 7 | 8 | it 'validates comment presence' do 9 | expect(build_stubbed(:comment)).to validate_presence_of(:comment) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # frozen_string_literal: true 4 | 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 13 | 14 | Dir.chdir app_root 15 | exec 'bin/rails', *ARGV 16 | -------------------------------------------------------------------------------- /db/migrate/20100406085611_create_comment_types.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateCommentTypes < SolidusSupport::Migration[4.2] 4 | def self.up 5 | create_table :comment_types do |t| 6 | t.string :name 7 | t.string :applies_to 8 | 9 | t.timestamps 10 | end 11 | end 12 | 13 | def self.down 14 | drop_table :comment_types 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/solidus_comments/engine.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spree/core' 4 | 5 | module SolidusComments 6 | class Engine < Rails::Engine 7 | include SolidusSupport::EngineExtensions 8 | 9 | isolate_namespace Spree 10 | 11 | engine_name 'solidus_comments' 12 | 13 | # use rspec for tests 14 | config.generators do |g| 15 | g.test_framework :rspec 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/models/spree/comment.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Spree 4 | class Comment < ApplicationRecord 5 | belongs_to :commentable, polymorphic: true 6 | belongs_to :comment_type, optional: true 7 | belongs_to :user 8 | 9 | default_scope { order "created_at ASC" } 10 | 11 | scope :recent, -> { reorder "created_at DESC" } 12 | 13 | validates :comment, presence: true 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /config/locales/ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | said: сказал 3 | for: для 4 | comments: Комментарии 5 | comment: Комментарий 6 | add_comment: Добавить комментарий 7 | add_comment_type: Добавить тип комментария 8 | comment_types: Типы комментариев 9 | manage_comment_types: Администрирование типов комментариев 10 | applies_to: Применить к 11 | new_comment_type: Новый тип комментария 12 | editing_comment_type: Редактировать тип комментария 13 | -------------------------------------------------------------------------------- /app/controllers/spree/admin/comments_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Spree 4 | module Admin 5 | class CommentsController < Spree::Admin::ResourceController 6 | private 7 | 8 | def render_after_create_error 9 | flash.keep 10 | redirect_to request.referer 11 | end 12 | 13 | def location_after_save 14 | request.referer 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/support/feature_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module FeatureHelper 4 | def login_as_admin 5 | admin = create(:admin_user, password: 'test123', password_confirmation: 'test123') 6 | visit spree.admin_path 7 | fill_in 'Email', with: admin.email 8 | fill_in 'Password', with: 'test123' 9 | click_button 'Login' 10 | admin 11 | end 12 | end 13 | 14 | RSpec.configure do |config| 15 | config.include FeatureHelper, type: :feature 16 | end 17 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # frozen_string_literal: true 4 | 5 | require "bundler/setup" 6 | require "solidus_comments" 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__) 18 | -------------------------------------------------------------------------------- /app/decorators/models/solidus_comments/spree/shipment_decorator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SolidusComments 4 | module Spree 5 | module ShipmentDecorator 6 | # FIXME: 7 | # Shipments can have comments, but there is no admin interface to add new 8 | # shipment comments or view existing ones. 9 | # 10 | def self.prepended(base) 11 | base.acts_as_commentable 12 | end 13 | 14 | ::Spree::Shipment.prepend self 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/decorators/controllers/solidus_comments/spree/admin/orders_controller_decorator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SolidusComments 4 | module Spree 5 | module Admin 6 | module OrdersControllerDecorator 7 | def comments 8 | load_order 9 | 10 | @comment_types = 11 | ::Spree::CommentType.where applies_to: ::Spree::CommentType::ORDER 12 | end 13 | 14 | ::Spree::Admin::OrdersController.prepend self 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/views/spree/admin/shipments/comments.html.erb: -------------------------------------------------------------------------------- 1 | <%= render 'spree/admin/shared/order_tabs', :current => 'Shipments' %> 2 | 3 | <% content_for :page_title do %> 4 | <%= I18n.t('spree.shipments') %> #<%= @shipment.number%> (<%= I18n.t(@shipment.state.to_sym, :scope => :state_names, :default => @shipment.state.to_s.humanize) %>) 5 | <% end %> 6 | 7 | <%= render 'spree/admin/shared/comments', {:commentable => @shipment, :comments_for => "Shipment ##{@shipment.number}"} %> 8 | -------------------------------------------------------------------------------- /db/migrate/20091021182639_create_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateComments < SolidusSupport::Migration[4.2] 4 | def self.up 5 | create_table :comments do |t| 6 | t.string :title, limit: 50 7 | t.text :comment 8 | t.references :commentable, polymorphic: true 9 | t.references :user 10 | 11 | t.timestamps 12 | end 13 | 14 | add_index :comments, :commentable_type 15 | add_index :comments, :commentable_id 16 | add_index :comments, :user_id 17 | end 18 | 19 | def self.down 20 | drop_table :comments 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | --- 2 | en: 3 | spree: 4 | said: said 5 | for: for 6 | none: None 7 | comments: Comments 8 | comments_count: Comments (%{count}) 9 | comment: Comment 10 | commenter: Commenter 11 | add_comment: Add Comment 12 | add_comment_type: Add Comment Type 13 | comment_types: Comment Types 14 | manage_comment_types: Manage comment types 15 | applies_to: Applies To 16 | new_comment_type: New Comment Type 17 | editing_comment_type: Editing Comment Type 18 | back_to_comment_types_list: Back to Comment Types List 19 | commenter: Commenter 20 | -------------------------------------------------------------------------------- /app/overrides/spree/admin/shared/_order_submenu/add_comment_to_admin_orders_tabs.html.erb.deface: -------------------------------------------------------------------------------- 1 | 2 | 3 |
  • > 4 | <% if @order.comments.any? %> 5 | <%= link_to_with_icon "comment-o", 6 | I18n.t("spree.comments_count", count: @order.comments.count), 7 | comments_admin_order_url(@order) %> 8 | <% else %> 9 | <%= link_to_with_icon "comment-o", 10 | I18n.t("spree.comments"), 11 | comments_admin_order_url(@order) %> 12 | <% end %> 13 |
  • 14 | -------------------------------------------------------------------------------- /spec/features/admin/comment_types_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe 'Comment Types', :js do 6 | before { login_as_admin } 7 | 8 | it 'adds a menu item in settings' do 9 | visit spree.edit_admin_general_settings_path 10 | 11 | expect(page).to have_current_path "/admin/stores" 12 | expect(page).to have_text(/Comment Types/i) 13 | end 14 | 15 | it 'adds a new comment type' do 16 | visit spree.new_admin_comment_type_path 17 | 18 | fill_in 'Name', with: 'Some name' 19 | click_button 'Create' 20 | 21 | expect(page).to have_text('Some name') 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /app/views/spree/admin/comment_types/edit.html.erb: -------------------------------------------------------------------------------- 1 | <%= render :partial => 'spree/admin/shared/configuration_menu' %> 2 | 3 |
    4 |

    <%= I18n.t('spree.editing_comment_type') %>

    5 | <%= render 'spree/shared/error_messages', :target => @comment_type %> 6 |
    7 | 8 |
    9 | <%= form_for(@comment_type, :url => object_url, :html => { :method => :put }) do |f| %> 10 | <%= render :partial => 'form', :locals => { :f => f } %> 11 | 12 |
    13 | <%= render :partial => 'spree/admin/shared/edit_resource_links' %> 14 |
    15 | <% end %> 16 |
    17 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: wontfix 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false -------------------------------------------------------------------------------- /lib/acts_as_commentable/commentable_methods.rb: -------------------------------------------------------------------------------- 1 | require 'active_record' 2 | 3 | # ActsAsCommentable 4 | module Juixe 5 | module Acts 6 | module Commentable 7 | extend ActiveSupport::Concern 8 | 9 | class_methods do 10 | def acts_as_commentable(*args) 11 | options = args.to_a.flatten.compact.partition { |opt| opt.kind_of? Hash } 12 | 13 | join_options = options.first.blank? ? [{}] : options.first 14 | throw "Only one set of options can be supplied for the join" if join_options.length > 1 15 | join_options = join_options.first 16 | 17 | has_many :comments, 18 | **{ as: :commentable, dependent: :destroy }.merge(join_options) 19 | end 20 | end 21 | 22 | ActiveRecord::Base.include self 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/generators/solidus_comments/install/install_generator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SolidusComments 4 | module Generators 5 | class InstallGenerator < Rails::Generators::Base 6 | class_option :auto_run_migrations, type: :boolean, default: false 7 | 8 | def add_migrations 9 | run 'bundle exec rake railties:install:migrations FROM=solidus_comments' 10 | end 11 | 12 | def run_migrations 13 | run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask('Would you like to run the migrations now? [Y/n]')) 14 | if run_migrations 15 | run 'bundle exec rake db:migrate' 16 | else 17 | puts 'Skipping rake db:migrate, don\'t forget to run it!' # rubocop:disable Rails/Output 18 | end 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Configure Rails Environment 4 | ENV['RAILS_ENV'] = 'test' 5 | 6 | # Run Coverage report 7 | require 'solidus_dev_support/rspec/coverage' 8 | 9 | require File.expand_path('dummy/config/environment.rb', __dir__) 10 | 11 | # Requires factories and other useful helpers defined in spree_core. 12 | require 'solidus_dev_support/rspec/feature_helper' 13 | 14 | # Requires supporting ruby files with custom matchers and macros, etc, 15 | # in spec/support/ and its subdirectories. 16 | Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each { |f| require f } 17 | 18 | SolidusDevSupport::TestingSupport::Factories.load_for(SolidusComments::Engine) 19 | 20 | RSpec.configure do |config| 21 | config.infer_spec_type_from_file_location! 22 | config.use_transactional_fixtures = false 23 | end 24 | -------------------------------------------------------------------------------- /app/views/spree/admin/comment_types/new.html.erb: -------------------------------------------------------------------------------- 1 | <%= render :partial => 'spree/admin/shared/configuration_menu' %> 2 | 3 | <% content_for :page_title do %> 4 | <%= I18n.t('spree.new_comment_type') %> 5 | <% end %> 6 | 7 | <% content_for :page_actions do %> 8 |
  • 9 | <%= link_to I18n.t('spree.back_to_comment_types_list'), admin_comment_types_path, :icon => 'icon-arrow-left' %> 10 |
  • 11 | <% end %> 12 | 13 | <%= render :partial => 'spree/shared/error_messages', :locals => { :target => @comment_type } %> 14 | 15 | <%= form_for(:comment_type, :url => collection_url) do |f| %> 16 |
    17 | <%= render :partial => 'form', :locals => { :f => f } %> 18 |
    19 | <%= button_tag I18n.t('spree.create'), class: 'fa fa-icon-ok button' %> 20 |
    21 |
    22 | <% end %> 23 | -------------------------------------------------------------------------------- /app/views/spree/admin/comment_types/_form.html.erb: -------------------------------------------------------------------------------- 1 |
    2 | <%= f.field_container :name do %> 3 | <%= f.label :name, I18n.t('spree.name') %>
    4 | <%= f.text_field :name, :class => 'fullwidth title' %> 5 | <%= error_message_on :comment_type, :name %> 6 | <% end %> 7 | 8 | <%= f.field_container :applies_to do %> 9 | <%= f.label :applies_to, I18n.t('spree.applies_to') %>
    10 | <% 11 | # FIXME: 12 | # This text field is an error prone. We should provide a drop-down menu 13 | # that only lists models that have `acts_as_commentable` enabled on them. 14 | # 15 | %> 16 | <%= f.text_field :applies_to, 17 | class: "fullwidth title", 18 | value: (f.object&.applies_to || Spree::CommentType::ORDER) %> 19 | <%= error_message_on :comment_type, :applies_to %> 20 | <% end %> 21 |
    22 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | git_source(:github) { |repo| "https://github.com/#{repo}.git" } 5 | 6 | branch = ENV.fetch('SOLIDUS_BRANCH', 'main') 7 | gem 'solidus', github: "solidusio/solidus", branch: branch 8 | 9 | if (branch == 'main') || (branch >= 'v3.2') 10 | gem "solidus_frontend" 11 | else 12 | gem "solidus_frontend", github: "solidusio/solidus", branch: branch 13 | end 14 | 15 | # Needed to help Bundler figure out how to resolve dependencies, 16 | # otherwise it takes forever to resolve them. 17 | # See https://github.com/bundler/bundler/issues/6677 18 | gem 'rails', '>0.a' 19 | 20 | # Provides basic authentication functionality for testing parts of your engine 21 | gem 'solidus_auth_devise' 22 | 23 | case ENV['DB'] 24 | when 'mysql' 25 | gem 'mysql2' 26 | when 'postgresql' 27 | gem 'pg' 28 | else 29 | gem 'sqlite3' 30 | end 31 | 32 | gemspec 33 | -------------------------------------------------------------------------------- /spec/model/spree/order_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | RSpec.describe Spree::Order do 4 | let(:order) { create :order } 5 | let(:user) { create :admin_user } 6 | 7 | describe "acts_as_commentable" do 8 | describe "#comments" do 9 | subject { order.comments } 10 | 11 | context "when there are no comments" do 12 | it { is_expected.to be_empty } 13 | end 14 | 15 | context "when there are comments" do 16 | it "returns a collection of comments" do 17 | expect { 18 | order.comments.create! title: "Title", 19 | comment: "Comment.", 20 | user: user 21 | } 22 | .to change { order.reload.comments.to_a } 23 | .from([]) 24 | .to([instance_of(Spree::Comment)]) 25 | 26 | expect(order.comments.first.attributes).to include( 27 | "title" => "Title", 28 | "comment" => "Comment.", 29 | "user_id" => user.id 30 | ) 31 | end 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/model/spree/shipment_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | RSpec.describe Spree::Shipment do 4 | let(:shipment) { create :shipment } 5 | let(:user) { create :admin_user } 6 | 7 | describe "acts_as_commentable" do 8 | describe "#comments" do 9 | subject { shipment.comments } 10 | 11 | context "when there are no comments" do 12 | it { is_expected.to be_empty } 13 | end 14 | 15 | context "when there are comments" do 16 | it "returns a collection of comments" do 17 | expect { 18 | shipment.comments.create! title: "Title", 19 | comment: "Comment.", 20 | user: user 21 | } 22 | .to change { shipment.reload.comments.to_a } 23 | .from([]) 24 | .to([instance_of(Spree::Comment)]) 25 | 26 | expect(shipment.comments.first.attributes).to include( 27 | "title" => "Title", 28 | "comment" => "Comment.", 29 | "user_id" => user.id 30 | ) 31 | end 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /app/views/spree/admin/shared/_comment_list.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | <% commentable.comments.reverse.each_with_index do |comment, index| %> 18 | 19 | 20 | 21 | 22 | 23 | 24 | <% end %> 25 | 26 |
    <%= "#{t('spree.date')}/#{t('spree.time')}" %><%= I18n.t('spree.type') %><%= I18n.t('spree.commenter') %><%= I18n.t('spree.comment') %>
    <%= pretty_time(comment.created_at) %><%= comment.comment_type.try(:name) || I18n.t('spree.none') %><%= comment.user.try(:email) %><%= comment.comment.html_safe %>
    27 | -------------------------------------------------------------------------------- /lib/acts_as_commentable/MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006 Cosmin Radoi 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Solidus Comments 2 | ============== 3 | 4 | [![CircleCI](https://circleci.com/gh/solidusio-contrib/solidus_comments.svg?style=svg)](https://circleci.com/gh/solidusio-contrib/solidus_comments) 5 | 6 | Solidus Comments is an extension for Solidus to allow commenting on different models via the 7 | admin ui and currently supports Orders & Shipments. 8 | 9 | Solidus Comments also supports optional comment Types which can be defined per comment-able 10 | object (i.e. Order, Shipment, etc) via the admin Configuration tab. 11 | 12 | This is based on a fork / rename of jderrett/spree-order-comments, and subsequently spree/spree-comments 13 | 14 | Notes: 15 | 16 | * Comments are create-only. You cannot edit or remove them from the Admin UI. 17 | 18 | Installation 19 | ------------ 20 | 21 | Add the following to your Gemfile (or check Versionfile for Solidus versions requirements): 22 | 23 | gem "solidus_comments" 24 | 25 | Run: 26 | 27 | ```shell 28 | bundle install 29 | bundle exec rails g solidus_comments:install 30 | ``` 31 | 32 | Run the migrations if you did not during the installation generator: 33 | 34 | bundle exec rake db:migrate 35 | 36 | Start your server: 37 | 38 | rails s 39 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | browser-tools: circleci/browser-tools@1.4 5 | 6 | # Always take the latest version of the orb, this allows us to 7 | # run specs against Solidus supported versions only without the need 8 | # to change this configuration every time a Solidus version is released 9 | # or goes EOL. 10 | solidusio_extensions: solidusio/extensions@volatile 11 | 12 | jobs: 13 | run-specs-with-postgres: 14 | executor: solidusio_extensions/postgres 15 | steps: 16 | - browser-tools/install-chrome: 17 | chrome-version: 123.0.6312.105 18 | replace-existing: true 19 | - solidusio_extensions/run-tests 20 | run-specs-with-mysql: 21 | executor: solidusio_extensions/mysql 22 | steps: 23 | - browser-tools/install-chrome: 24 | chrome-version: 123.0.6312.105 25 | replace-existing: true 26 | - solidusio_extensions/run-tests 27 | 28 | workflows: 29 | "Run specs on supported Solidus versions": 30 | jobs: 31 | - run-specs-with-postgres 32 | - run-specs-with-mysql 33 | "Weekly run specs against master": 34 | triggers: 35 | - schedule: 36 | cron: "0 0 * * 4" # every Thursday 37 | filters: 38 | branches: 39 | only: 40 | - master 41 | jobs: 42 | - run-specs-with-postgres 43 | - run-specs-with-mysql 44 | -------------------------------------------------------------------------------- /solidus_comments.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | $:.push File.expand_path('lib', __dir__) 4 | require 'solidus_comments/version' 5 | 6 | Gem::Specification.new do |s| 7 | s.name = 'solidus_comments' 8 | s.version = SolidusComments::VERSION 9 | s.summary = 'Adds comments to the solidus admin' 10 | s.license = 'BSD-3-Clause' 11 | 12 | s.author = ['Rails Dog', 'Solidus Contrib'] 13 | s.email = 'contact@solidus.io' 14 | s.homepage = 'https://github.com/solidusio-contrib/solidus_comments' 15 | 16 | if s.respond_to?(:metadata) 17 | s.metadata["homepage_uri"] = s.homepage if s.homepage 18 | s.metadata["source_code_uri"] = s.homepage if s.homepage 19 | end 20 | 21 | s.required_ruby_version = '>= 2.5' 22 | 23 | s.files = Dir.chdir(File.expand_path(__dir__)) do 24 | `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 25 | end 26 | s.test_files = Dir['spec/**/*'] 27 | s.bindir = "exe" 28 | s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) } 29 | s.require_paths = ["lib"] 30 | 31 | s.add_dependency 'deface', '~> 1.5' 32 | s.add_dependency 'solidus_core', ['>= 2.0.0', '< 5'] 33 | s.add_dependency 'solidus_backend', ['>= 2.0.0', '< 5'] 34 | s.add_dependency 'solidus_support', '~> 0.5' 35 | 36 | s.add_development_dependency 'solidus_dev_support' 37 | s.add_development_dependency 'shoulda-matchers', '~> 4.0' 38 | end 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Rails Dog 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 Solidus 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. 27 | -------------------------------------------------------------------------------- /spec/model/spree/comment_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | RSpec.describe Spree::Comment do 4 | let(:commentable) { create :shipment } 5 | let(:user) { create :admin_user } 6 | 7 | let!(:older_comment) { 8 | comment = described_class.create! comment: "Text", 9 | commentable: commentable, 10 | user: user 11 | comment.update_column :created_at, 10.days.ago 12 | comment 13 | } 14 | let!(:newer_comment) { 15 | comment = described_class.create! comment: "Text", 16 | commentable: commentable, 17 | user: user 18 | comment.update_column :created_at, 1.minute.ago 19 | comment 20 | } 21 | 22 | describe ".all" do 23 | subject { described_class.all } 24 | 25 | it "returns comments in chronological order" do 26 | expect(subject).to eq [older_comment, newer_comment] 27 | end 28 | end 29 | 30 | describe ".recent" do 31 | subject { described_class.recent } 32 | 33 | it "returns comments in reverse-chronological order" do 34 | expect(subject).to eq [newer_comment, older_comment] 35 | end 36 | end 37 | 38 | describe "#valid?" do 39 | subject { comment.valid? } 40 | 41 | context "when the comment is empty" do 42 | let(:comment) { 43 | described_class.new comment: nil, 44 | commentable: commentable, 45 | user: user 46 | } 47 | 48 | it { is_expected.to eq false } 49 | end 50 | 51 | context "when the comment has text" do 52 | let(:comment) { 53 | described_class.new comment: "Text", 54 | commentable: commentable, 55 | user: user 56 | } 57 | 58 | it { is_expected.to eq true } 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /app/views/spree/admin/comment_types/index.html.erb: -------------------------------------------------------------------------------- 1 | <%= render :partial => 'spree/admin/shared/configuration_menu' %> 2 | 3 | <% content_for :page_title do %> 4 | <%= I18n.t('spree.comment_types') %> 5 | <% end %> 6 | 7 | <% content_for :page_actions do %> 8 |
  • 9 | <%= link_to I18n.t('spree.new_comment_type'), new_object_url, :icon => 'icon-plus', :id => 'admin_new_comment_type_link' %> 10 |
  • 11 | <% end %> 12 | 13 | <% if @comment_types.any? %> 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | <% @comment_types.each do |comment_type| %> 29 | 30 | 31 | 32 | 33 | 37 | 38 | <% end %> 39 | 40 |
    <%= I18n.t('spree.name') %><%= I18n.t('spree.applies_to') %>
    <%= comment_type.name %><%= comment_type.applies_to %> 34 | <%= link_to_edit comment_type, :no_text => true %> 35 | <%= link_to_delete comment_type, :no_text => true %> 36 |
    41 | <% else %> 42 |
    43 | <%= I18n.t('spree.no_resource_found', resource: I18n.t(:comment_types, scope: 'spree')) %>, 44 | <%= link_to I18n.t('spree.add_one'), spree.new_admin_comment_type_path %>! 45 |
    46 | <% end %> 47 | -------------------------------------------------------------------------------- /app/views/spree/admin/shared/_comments.html.erb: -------------------------------------------------------------------------------- 1 | <% if commentable.comments.any? %> 2 | <%= render 'spree/admin/shared/comment_list', :commentable => commentable %> 3 | <% else %> 4 |
    5 | <%= I18n.t('spree.no_resource_found', resource: I18n.t(:comments, scope: 'spree')) %> 6 |
    7 | <% end %> 8 | 9 | <% if can? :create, commentable.comments.build %> 10 |
    11 | <%= form_for(:comment, :url => admin_comments_url) do |f| %> 12 | <%= hidden_field_tag 'comment[commentable_id]', commentable.id %> 13 | <%= hidden_field_tag 'comment[commentable_type]', commentable.class %> 14 | <%= hidden_field_tag 'comment[user_id]', spree_current_user.id %> 15 | 16 |
    17 |
    18 | <%= I18n.t('spree.add_comment') %> 19 | 20 |
    21 |
    22 | <% if @comment_types.present? %> 23 |
    24 | <%= f.label :comment_type_id, I18n.t('spree.type') %> 25 | <%= f.select :comment_type_id, @comment_types.map{|ct| [ct.name, ct.id]},{} ,:class => 'fullwidth' %> 26 |
    27 | <% end %> 28 |
    29 | <%= f.label :comment, I18n.t('spree.comment') %> 30 | <%= f.text_area :comment, :style => 'height:150px;', :class => 'fullwidth' %> 31 |
    32 |
    33 |
    34 |
    35 | 36 |
    37 | 38 |
    39 | <%= f.submit I18n.t('spree.add_comment') %> 40 |
    41 |
    42 | <% end %> 43 |
    44 | <% end %> 45 | -------------------------------------------------------------------------------- /spec/features/admin/order_comments_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # FIXME: 4 | # None of these tests exercise creating or viewing comments with an assigned 5 | # comment type. 6 | # 7 | require 'spec_helper' 8 | RSpec.describe 'Order Comments', :js do 9 | let!(:order) { create(:completed_order_with_totals) } 10 | 11 | before do 12 | login_as_admin 13 | end 14 | 15 | it 'adding comments to an order' do 16 | visit spree.comments_admin_order_path(order) 17 | expect(page).to have_text(/No Comments found/i) 18 | 19 | click_button 'Add Comment' 20 | expect(page).to have_text('Comment can\'t be blank') 21 | 22 | fill_in 'Comment', with: 'A test comment.' 23 | click_button 'Add Comment' 24 | 25 | within "table.solidus-comments-comment-list" do 26 | expect(page).to have_text "A test comment" 27 | end 28 | end 29 | 30 | context 'without permission' do 31 | let(:comment) { order.comments.new } 32 | 33 | before do 34 | # Stub for not allowing user to have comment permissions on the order. 35 | # Works with just the default stub for multiple instances. 36 | allow_any_instance_of(CanCan::Ability) 37 | .to receive(:can?).and_return(false) 38 | # Stub normal permissions in order to override create comment permission. 39 | allow_any_instance_of(CanCan::Ability) 40 | .to receive(:can?).with(:admin, Spree::Order).and_return(true) 41 | allow_any_instance_of(CanCan::Ability) 42 | .to receive(:can?).with(:comments, Spree::Order).and_return(true) 43 | allow_any_instance_of(CanCan::Ability) 44 | .to receive(:can?).with(:update, order).and_return(true) 45 | allow_any_instance_of(CanCan::Ability) 46 | .to receive(:can?).with(:display, Spree::Adjustment).and_return(true) 47 | allow_any_instance_of(CanCan::Ability) 48 | .to receive(:can?).with(:display, Spree::Payment).and_return(true) 49 | allow_any_instance_of(CanCan::Ability) 50 | .to receive(:can?) 51 | .with(:display, Spree::ReturnAuthorization).and_return(true) 52 | allow_any_instance_of(CanCan::Ability) 53 | .to receive(:can?) 54 | .with(:display, Spree::CustomerReturn).and_return(true) 55 | allow_any_instance_of(CanCan::Ability) 56 | .to receive(:can?) 57 | .with(:manage, Spree::OrderCancellations).and_return(true) 58 | end 59 | 60 | it 'does not display form' do 61 | visit spree.comments_admin_order_path(order) 62 | 63 | expect(page).to have_text(/No Comments found/i) 64 | expect(page).not_to have_text 'Add Comment' 65 | end 66 | end 67 | end 68 | --------------------------------------------------------------------------------