Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add time-based slides #34

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
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