diff --git a/.travis.yml b/.travis.yml index b11346b..4a53bc3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,12 @@ gemfile: - gemfiles/spree_3_2.gemfile - gemfiles/spree_master.gemfile +before_script: + - mkdir ../temp; cd ../temp + - bundle exec rails _5.1.1_ plugin new spree_slider --mountable --dummy-path=spec/dummy --skip-test-unit + - mv spree_slider/spec/dummy ../spec/ + - cd ../build; rm -rf ../temp + script: - bundle exec rspec spec diff --git a/app/controllers/spree/admin/slides_controller.rb b/app/controllers/spree/admin/slides_controller.rb index 4a86b4c..0c13da4 100644 --- a/app/controllers/spree/admin/slides_controller.rb +++ b/app/controllers/spree/admin/slides_controller.rb @@ -18,7 +18,16 @@ def location_after_save end def slide_params - params.require(:slide).permit(:name, :body, :link_url, :published, :image, :position, :product_id) + params.require(:slide) + .permit(:name, + :body, + :link_url, + :published, + :image, + :position, + :product_id, + :starts_at, + :ends_at) end end end diff --git a/app/models/spree/slide.rb b/app/models/spree/slide.rb index c8d8774..c5df8bf 100644 --- a/app/models/spree/slide.rb +++ b/app/models/spree/slide.rb @@ -1,5 +1,4 @@ class Spree::Slide < ActiveRecord::Base - has_and_belongs_to_many :slide_locations, class_name: 'Spree::SlideLocation', join_table: 'spree_slide_slide_locations' @@ -8,13 +7,21 @@ class Spree::Slide < ActiveRecord::Base url: '/spree/slides/:id/:style/:basename.:extension', path: ':rails_root/public/spree/slides/:id/:style/:basename.:extension', convert_options: { all: '-strip -auto-orient -colorspace sRGB' } - validates_attachment :image, content_type: { content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"] } + validates_attachment :image, content_type: { content_type: ['image/jpg', 'image/jpeg', 'image/png', 'image/gif'] } scope :published, -> { where(published: true).order('position ASC') } - scope :location, -> (location) { joins(:slide_locations).where('spree_slide_locations.name = ?', location) } + scope :location, ->(location) { joins(:slide_locations).where('spree_slide_locations.name = ?', location) } belongs_to :product, touch: true + def self.active_for_current_time + where '(starts_at is NULL AND ends_at is NULL) + OR (starts_at <= ? AND ends_at is NULL) + OR (starts_at is NULL AND ends_at >= ?) + OR (starts_at <= ? AND ends_at >= ?)', + *([Time.current] * 4) + end + def initialize(attrs = nil) attrs ||= { published: true } super @@ -31,4 +38,8 @@ def slide_link def slide_image !image.file? && product.present? && product.images.any? ? product.images.first.attachment : image end + + def active_now? + Time.current.between?(starts_at || 1.second.ago, ends_at || 1.second.from_now) + end end diff --git a/app/models/spree/slide_location.rb b/app/models/spree/slide_location.rb index 6993052..04b5b3f 100644 --- a/app/models/spree/slide_location.rb +++ b/app/models/spree/slide_location.rb @@ -1,9 +1,10 @@ class Spree::SlideLocation < ActiveRecord::Base - has_and_belongs_to_many :slides, + ->(model) { where('spree_slides.id != ?', model.fallback_slide_id || 0) }, class_name: 'Spree::Slide', join_table: 'spree_slide_slide_locations' - validates :name, presence: true + belongs_to :fallback_slide, class_name: 'Spree::Slide', foreign_key: 'fallback_slide_id' + validates :name, presence: true end diff --git a/app/views/spree/admin/slide_locations/_form.html.erb b/app/views/spree/admin/slide_locations/_form.html.erb index 593aa1a..b6daef6 100644 --- a/app/views/spree/admin/slide_locations/_form.html.erb +++ b/app/views/spree/admin/slide_locations/_form.html.erb @@ -5,6 +5,12 @@ <%= f.label :name, t(:name) %>
<%= f.text_field :name, class: "form-control fullwidth" %> <% end %> + + <%= f.field_container :fallback_slide_id do %> + <%= f.label :fallback_slide_id, 'Fallback slide' %>
+
This slide will be shown only when no other slide can be shown.
+ <%= f.collection_select(:fallback_slide_id, Spree::Slide.all.order(:name), :id, :name, { include_blank: Spree.t('match_choices.none') }, { class: 'select2', disabled: (cannot? :edit, Spree::SlideLocation) }) %> + <% end %> diff --git a/app/views/spree/admin/slide_locations/index.html.erb b/app/views/spree/admin/slide_locations/index.html.erb index f45ee4c..e99b967 100644 --- a/app/views/spree/admin/slide_locations/index.html.erb +++ b/app/views/spree/admin/slide_locations/index.html.erb @@ -10,6 +10,7 @@ <%= Spree.t(:name) %> + Fallback slide @@ -17,6 +18,14 @@ <% @slide_locations.each do |location|%> <%= location.name %> + + <% if location.fallback_slide %> + <%= image_tag location.fallback_slide.try(:slide_image), style: 'width: 120px; height: auto;' %> + <%= link_to location.fallback_slide.name, admin_slide_path(location.fallback_slide) %> + <% else %> + None + <% end %> + <%= link_to_edit location, no_text: true, class: 'edit' %>   diff --git a/app/views/spree/admin/slides/_form.html.erb b/app/views/spree/admin/slides/_form.html.erb index 529321e..5ca0bd3 100644 --- a/app/views/spree/admin/slides/_form.html.erb +++ b/app/views/spree/admin/slides/_form.html.erb @@ -36,6 +36,22 @@ <% end %> +
+ <%= f.field_container :starts_at do %> + <%= f.label :starts_at, 'Starts at' %>
+
The slide will not be shown before this date, even if published
+ <%= f.date_field :starts_at, class: 'fullwidth form-control' %>
+ <% end %> +
+ +
+ <%= f.field_container :ends_at do %> + <%= f.label :ends_at, 'Ends at' %>
+
The slide will not be shown after this date, even if published
+ <%= f.date_field :ends_at, class: 'fullwidth form-control' %>
+ <% end %> +
+
<%= render 'spree/admin/slides/edit_slider_locations', f: f %>
diff --git a/db/migrate/20170906023647_add_starts_at_and_ends_at_columns_to_spree_slides.rb b/db/migrate/20170906023647_add_starts_at_and_ends_at_columns_to_spree_slides.rb new file mode 100644 index 0000000..75eb33c --- /dev/null +++ b/db/migrate/20170906023647_add_starts_at_and_ends_at_columns_to_spree_slides.rb @@ -0,0 +1,6 @@ +class AddStartsAtAndEndsAtColumnsToSpreeSlides < ActiveRecord::Migration + def change + add_column :spree_slides, :starts_at, :datetime + add_column :spree_slides, :ends_at, :datetime + end +end diff --git a/db/migrate/20170907185000_add_fallback_slide_column.rb b/db/migrate/20170907185000_add_fallback_slide_column.rb new file mode 100644 index 0000000..312a6ac --- /dev/null +++ b/db/migrate/20170907185000_add_fallback_slide_column.rb @@ -0,0 +1,5 @@ +class AddFallbackSlideColumn < ActiveRecord::Migration + def change + add_column 'spree_slide_locations', :fallback_slide_id, :integer, default: nil + end +end diff --git a/spec/models/spree/slide_location_spec.rb b/spec/models/spree/slide_location_spec.rb new file mode 100644 index 0000000..608434a --- /dev/null +++ b/spec/models/spree/slide_location_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +RSpec.describe Spree::SlideLocation do + let(:slide1) { Spree::Slide.create } + let(:slide2) { Spree::Slide.create } + + describe '#slides' do + before do + Spree::SlideLocation.create name: 'Test location', + slides: [slide1, slide2], + fallback_slide: slide1 + end + + it 'doesnt include its fallback slide' do + location = Spree::SlideLocation.find_by! name: 'Test location' + expect(location.slides.map(&:id)).to contain_exactly slide2.id + end + end +end diff --git a/spec/models/spree/slide_spec.rb b/spec/models/spree/slide_spec.rb new file mode 100644 index 0000000..40ad1e5 --- /dev/null +++ b/spec/models/spree/slide_spec.rb @@ -0,0 +1,68 @@ +require 'spec_helper' + +RSpec.describe Spree::Slide do + describe '#active_now?' do + context 'when both starts_at and ends_at are nil' do + subject { Spree::Slide.new starts_at: nil, ends_at: nil } + + it { is_expected.to be_active_now } + end + + context 'when starts_at is in the past and ends_at is nil' do + subject { Spree::Slide.new starts_at: 2.days.ago, ends_at: nil } + + it { is_expected.to be_active_now } + end + + context 'when starts_at is in the future and ends_at is nil' do + subject { Spree::Slide.new starts_at: 2.days.from_now, ends_at: nil } + + it { is_expected.not_to be_active_now } + end + + context 'when starts_at is nil and ends_at is in the future' do + subject { Spree::Slide.new starts_at: nil, ends_at: 2.days.from_now } + + it { is_expected.to be_active_now } + end + + context 'when starts_at is nil and ends_at is in the past' do + subject { Spree::Slide.new starts_at: nil, ends_at: 2.days.ago } + + it { is_expected.not_to be_active_now } + end + + context 'when both starts_at and end_at is in the past' do + subject { Spree::Slide.new starts_at: 2.days.ago, ends_at: 1.day.ago } + + it { is_expected.not_to be_active_now } + end + + context 'when starts_at is in the past and end_at is in the future' do + subject { Spree::Slide.new starts_at: 2.days.ago, ends_at: 2.days.from_now } + + it { is_expected.to be_active_now } + end + end + + describe '.active_for_current_time' do + it 'returns all the slides from the database that are active for current time' do + good_slides = [ + Spree::Slide.create(starts_at: nil, ends_at: nil), + Spree::Slide.create(starts_at: 2.days.ago, ends_at: nil), + Spree::Slide.create(starts_at: nil, ends_at: 2.days.from_now), + Spree::Slide.create(starts_at: 2.days.ago, ends_at: 2.days.from_now) + ].map(&:id) + + bad_slides = [ + Spree::Slide.create(starts_at: 2.days.from_now, ends_at: nil), + Spree::Slide.create(starts_at: nil, ends_at: 2.days.ago), + Spree::Slide.create(starts_at: 2.days.ago, ends_at: 1.day.ago) + ].map(&:id) + + slides = Spree::Slide.active_for_current_time.map(&:id) + expect(slides).to include *good_slides + expect(slides).not_to include *bad_slides + end + end +end