Skip to content
This repository has been archived by the owner on Jun 27, 2020. It is now read-only.

Feature/15 once assigned lists are locked #17

Merged
merged 10 commits into from
Aug 27, 2016
21 changes: 13 additions & 8 deletions app/controllers/member/lists_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class Member::ListsController < Member::BaseController

before_filter :check_if_gift_day_has_passed, only: [:edit, :update, :destroy]
before_filter :check_if_gift_day_has_passed_or_locked, only: [:lock_and_assign, :edit, :update, :destroy]

def new
@list = current_user.lists.build
Expand All @@ -16,12 +16,11 @@ def create
end

def lock_and_assign
@list = List.find(params[:list_id])
find_list
authorize!(:update, @list)
if @list.santas.count > 3
if @list.santas.count >= 3
List::ShuffleAndAssignSantas.new(@list).assign_and_email
flash.now[:success] = 'Recipients set and Santas notified'
#TODO Lock the list preventing further changes
else
flash.now[:danger] = 'You must have at least three Santas in the list first!'
end
Expand Down Expand Up @@ -61,13 +60,19 @@ def list_params
end

def find_list
@list = List.find(params[:id])
if params.include?("list_id")
@list = List.find(params[:list_id])
else
@list = List.find(params[:id])
end
end

def check_if_gift_day_has_passed
def check_if_gift_day_has_passed_or_locked
find_list
if Time.now > @list.gift_day
flash[:warning] = 'Sorry! As the gift day has passed, you can no longer modify or delete this list!'
if Time.current > @list.gift_day || @list.is_locked
flash[:warning] =
'Sorry! You can no longer modify or delete this list!
Either the list is locked or the gift day has passed.'
redirect_to member_dashboard_index_path
end
end
Expand Down
9 changes: 9 additions & 0 deletions app/models/list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,20 @@ class List < ActiveRecord::Base
validates :gift_day, presence: true

validate :gift_day_cannot_be_in_the_past, on: :create
validate :cannot_be_changed, on: :update

def gift_day_cannot_be_in_the_past
if gift_day.present? && gift_day < Time.zone.today
errors.add(:gift_day, "You can't set the gift day to be in the past")
end
end

private

def cannot_be_changed
if is_locked
errors.add(:is_locked, "List has been locked and Santas already emailed.")
end
end

end
48 changes: 25 additions & 23 deletions app/models/list/shuffle_and_assign_santas.rb
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
# This is the class which handles the organising of santas and recipients
class List
class ShuffleAndAssignSantas
def initialize(list)
@list = list
@santas = @list.santas.to_a
end
# This class handles the organising of santas and recipients
class List::ShuffleAndAssignSantas

def initialize(list)
@list = list
@santas = @list.santas.to_a
end

def assign_and_email
randomise_and_assign(@santas)
@santas.each do |santa|
AssignmentMailer.send_assignment(santa).deliver_later
end
def assign_and_email
randomise_and_assign(@santas)
@santas.each do |santa|
AssignmentMailer.send_assignment(santa).deliver_later
end
# We override the validation here otherwise the is_locked validation kicks in
# which prevents us from saving the instance of list.
@list.update_attribute(:is_locked, true)
end

private
private

def randomise_and_assign(available_santas)
list_size = available_santas.size
shuffled_list = CircularList::List.new(available_santas.shuffle)
def randomise_and_assign(available_santas)
list_size = available_santas.size
shuffled_list = CircularList::List.new(available_santas.shuffle)

list_size.times do
santa = shuffled_list.fetch_previous
recipient = shuffled_list.fetch_next
list_size.times do
santa = shuffled_list.fetch_previous
recipient = shuffled_list.fetch_next

santa.giving_to = recipient.id
santa.save!
santa.giving_to = recipient.id
santa.save!

shuffled_list.fetch_next
end
shuffled_list.fetch_next
end
end
end
20 changes: 9 additions & 11 deletions app/views/layouts/application.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,14 @@
%header
.container
.navigation-wrapper
%ul.site-nav
= render "layouts/navigation"
.container
- flash.each do |key, value|
.flash-wrapper
-# the following two conditionals override devise
- if key == 'notice'
- key = 'success'
- if key == 'alert'
- key = 'danger'
.alert{class: "alert-#{key}"}= value
= render "layouts/navigation"
- flash.each do |key, value|
.flash-wrapper
-# the following two conditionals override devise
- if key == 'notice'
- key = 'success'
- if key == 'alert'
- key = 'danger'
.alert{class: "alert-#{key}"}= value

= content_for?(:content) ? yield(:content) : yield
7 changes: 5 additions & 2 deletions app/views/member/dashboard/index.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@
%td= list.name
%td.actions
= link_to "View", member_list_path(list), class: "btn btn-small btn-default"
= link_to "Edit", edit_member_list_path(list), class: "btn btn-small btn-default"
= link_to "Delete", member_list_path(list), method: :delete, data: { confirm: "Are you sure you want to delete this list?" }, class: "btn btn-small, btn-danger"
= link_to "Edit", edit_member_list_path(list), class: "btn btn-small btn-default",
disabled: list.is_locked || list.gift_day_cannot_be_in_the_past
= link_to "Delete", member_list_path(list), class: "btn btn-small, btn-danger",
data: { confirm: "Are you sure you want to delete this list?" },
method: :delete, disabled: list.is_locked || list.gift_day_cannot_be_in_the_past
18 changes: 18 additions & 0 deletions app/views/member/lists/_confirm_modal.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.modal-dialog{role: "document"}
.modal-content
.modal-header
%button.close{"aria-label" => "Close", "data-dismiss" => "modal", type: "button"}
%span{"aria-hidden" => "true"} ×
%h4#confirm_lock_and_sendLabel.modal-title Lock, assign and send
.modal-body
- not_enough = @list.santas.count < 3
%h3 Heads up!
%p By proceeding now, your list will be locked!
%p Your santas will be assigned someone and everyone in your list will be emailed.
%p Once this happens, there is no going back, so please be certain!
.modal-footer
%p= button_to "Lock, assign and send",
member_list_lock_and_assign_url(@list),
method: :patch, class: "btn btn-large btn-danger",
data: { disable_with: "Please wait..." },
disabled: (not_enough)
18 changes: 9 additions & 9 deletions app/views/member/lists/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@
- not_enough = @list.santas.count < 3

- if @list.santas.any?
%p Ready to set recipients for your list and lock it in?
%p
= button_to "Lock, assign and send",
member_list_lock_and_assign_url(@list),
method: :patch, class: "btn btn-large btn-danger",
data: { confirm: "Are you sure?" },
disabled: (not_enough)
- unless @list.is_locked
- if not_enough
%i= "Not available if there are less than three (3) Santas in your list"
%i= "Please add some more Santas to your list. We need at least three."
- else
%i Note this cannot be undone, please be certain!
%p Ready to set recipients for your list and lock it in?
%button.btn.btn-primary.btn-large.btn-danger{"data-target" => "#confirm_lock_and_send", "data-toggle" => "modal", type: "button"}
Lock, assign and send
#confirm_lock_and_send.modal.fade{"aria-labelledby" => "confirm_lock_and_sendLabel", role: "dialog", tabindex: "-1"}
= render 'confirm_modal'
- else
%i Note: List is locked. Santas have been assigned and emailed.

%table.table.table-hover
%thead
Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20160825144621_add_locked_to_list.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddLockedToList < ActiveRecord::Migration
def change
add_column :lists, :is_locked, :boolean, null: false, default: false
end
end
22 changes: 17 additions & 5 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,29 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20160815132705) do
ActiveRecord::Schema.define(version: 20160825144621) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

create_table "givers_receivers", id: false, force: :cascade do |t|
t.integer "giver_id", null: false
t.integer "receiver_id", null: false
t.integer "list_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

add_index "givers_receivers", ["giver_id"], name: "index_givers_receivers_on_giver_id", using: :btree
add_index "givers_receivers", ["receiver_id"], name: "index_givers_receivers_on_receiver_id", using: :btree

create_table "lists", force: :cascade do |t|
t.string "name", null: false
t.integer "user_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name", null: false
t.integer "user_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "gift_day"
t.boolean "is_locked", default: false, null: false
end

add_index "lists", ["created_at"], name: "index_lists_on_created_at", using: :btree
Expand Down
33 changes: 23 additions & 10 deletions spec/features/member/lists/member_can_delete_list_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,41 @@
visit member_dashboard_index_path
end

scenario "signed in user deletes existing list" do
scenario 'signed in user deletes existing list' do
# Ensure list exists before attempting to delete.
expect(page).to have_content(list.name)

within "table" do
click_on("Delete")
within 'table' do
click_on('Delete')
end

expect(page.find('.alert.alert-success')).to have_content("List was successfully deleted")
expect(page.find('.alert.alert-success')).to have_content('List was successfully deleted')
expect(page).to_not have_content(list.name)
expect(page).to have_content("You have no secret santa lists yet!")
expect(page).to have_content('You have no secret santa lists yet!')
end

context "the gift day has passed" do
scenario "user cannot delete list" do
context 'the gift day has passed' do
scenario 'user cannot delete list' do
list.update_attributes(gift_day: Date.yesterday)

within "table" do
click_on("Delete")
within 'table' do
click_on('Delete')
end

expect(page.find('.alert.alert-warning')).to have_content("Sorry! As the gift day has passed, you can no longer modify or delete this list!")
expect(page.find('.alert.alert-warning')).to have_content('Sorry! You can no longer modify or delete this list! Either the list is locked or the gift day has passed.')
expect(page).to have_content(list.name)
end
end

context 'the list has been locked' do
scenario 'user cannot delete list' do
list.update_attribute(:is_locked, true)

within 'table' do
click_on('Delete')
end

expect(page.find('.alert.alert-warning')).to have_content('Sorry! You can no longer modify or delete this list! Either the list is locked or the gift day has passed.')
expect(page).to have_content(list.name)
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/features/member/lists/member_can_edit_list_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
click_on("Edit")
end

expect(page.find('.alert.alert-warning')).to have_content("Sorry! As the gift day has passed, you can no longer modify or delete this list!")
expect(page.find('.alert.alert-warning')).to have_content("Sorry! You can no longer modify or delete this list! Either the list is locked or the gift day has passed.")
expect(page).to have_content(list.name)
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,22 @@

scenario 'user can lock the list and assign users', :js do
expect(page).to have_button('Lock, assign and send')
expect(page).to_not have_content('Not available if there are less than three (3) Santas in your list')
expect(page).to_not have_content('Please add some more Santas to your list. We need at least three.')

click_on('Lock, assign and send')
page.driver.browser.accept_confirm
# We click the button again in the modal that has popped up.
expect(page).to have_content("By proceeding now, your list will be locked!")

within('.modal-footer') do
click_on('Lock, assign and send')
end

expect(page).to have_flash :success, 'Recipients set and Santas notified'
expect(page).to have_content('Note: List is locked. Santas have been assigned and emailed.')
end

context 'where there are fewer than 3 santas in a list' do
let!(:santas) { FactoryGirl.create_list(:santa, 2, list_id: list.id) }

scenario 'the button should be disabled, with information' do
expect(page).to have_button('Lock, assign and send', disabled: true)
expect(page).to have_content('Not available if there are less than three (3) Santas in your list')
end
specify { expect(page).to have_content('Please add some more Santas to your list. We need at least three.') }
end
end
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
require 'rails_helper'

feature 'Member can view an existing list' do

let!(:list) { FactoryGirl.create(:list, user_id: user.id) }
let!(:user) { FactoryGirl.create(:user, :member) }
let!(:santa) { FactoryGirl.create(:santa, list: list) }
Expand All @@ -23,5 +22,4 @@
expect(page).to have_content(santa.email)
end
end

end
6 changes: 6 additions & 0 deletions spec/models/list/shuffle_and_assign_santas_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,11 @@
scenario 'each santa should recieve an email' do
expect { subject }.to change(ActionMailer::Base.deliveries, :count).by(5)
end

scenario 'the list should be locked after the method runs' do
expect(list.is_locked).to be_falsey
subject
expect(list.is_locked).to be_truthy
end
end
end
21 changes: 21 additions & 0 deletions spec/models/list_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,25 @@
end
end

describe "@cannot_be_changed" do
let!(:list) { FactoryGirl.create(:list, is_locked: status) }
let!(:santa) { FactoryGirl.create(:santa, list_id: list.id) }

context "where the list is locked" do
let(:status) { true }

it "should have errors" do
expect(list).to_not be_valid
expect(list.errors[:is_locked]).to be_present
expect(list.errors.count).to be(1)
expect(list.errors.first).to include("List has been locked and Santas already emailed.")
end
end

context "where the list is unlocked" do
let(:status) { false }
specify { expect(list).to be_valid }
end
end

end