Skip to content
6 changes: 6 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
11 changes: 10 additions & 1 deletion app/controllers/spree/admin/slides_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 14 additions & 3 deletions app/models/spree/slide.rb
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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
Expand All @@ -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
5 changes: 3 additions & 2 deletions app/models/spree/slide_location.rb
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions app/views/spree/admin/slide_locations/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
<%= f.label :name, t(:name) %><br>
<%= f.text_field :name, class: "form-control fullwidth" %>
<% end %>

<%= f.field_container :fallback_slide_id do %>
<%= f.label :fallback_slide_id, 'Fallback slide' %><br>
<div class="help-block">This slide will be shown only when no other slide can be shown.</div>
<%= 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 %>
</div>

</div>
9 changes: 9 additions & 0 deletions app/views/spree/admin/slide_locations/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,22 @@
<thead>
<tr data-hook="admin_slides_index_headers">
<th><%= Spree.t(:name) %></th>
<th>Fallback slide</th>
<th data-hook="admin_slides_index_header_actions" class="actions"></th>
</tr>
</thead>
<tbody>
<% @slide_locations.each do |location|%>
<tr>
<td class="align-center"><%= location.name %></td>
<td class="align-center">
<% 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 %>
</td>
<td data-hook="admin_slide_locations_index_row_actions" class="actions">
<%= link_to_edit location, no_text: true, class: 'edit' %>
&nbsp;
Expand Down
16 changes: 16 additions & 0 deletions app/views/spree/admin/slides/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,22 @@
<% end %>
</div>

<div class="col-md-6">
<%= f.field_container :starts_at do %>
<%= f.label :starts_at, 'Starts at' %><br>
<div class="help-block">The slide will not be shown before this date, even if published</div>
<%= f.date_field :starts_at, class: 'fullwidth form-control' %><br>
<% end %>
</div>

<div class="col-md-6">
<%= f.field_container :ends_at do %>
<%= f.label :ends_at, 'Ends at' %><br>
<div class="help-block">The slide will not be shown after this date, even if published</div>
<%= f.date_field :ends_at, class: 'fullwidth form-control' %><br>
<% end %>
</div>

<div class="col-md-6">
<%= render 'spree/admin/slides/edit_slider_locations', f: f %>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions db/migrate/20170907185000_add_fallback_slide_column.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddFallbackSlideColumn < ActiveRecord::Migration
def change
add_column 'spree_slide_locations', :fallback_slide_id, :integer, default: nil
end
end
19 changes: 19 additions & 0 deletions spec/models/spree/slide_location_spec.rb
Original file line number Diff line number Diff line change
@@ -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
68 changes: 68 additions & 0 deletions spec/models/spree/slide_spec.rb
Original file line number Diff line number Diff line change
@@ -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