From c512b079fa03764664e7e8007dc6f2bb3de7d550 Mon Sep 17 00:00:00 2001 From: Robert Landreaux Date: Sat, 17 Jan 2015 00:20:11 -0500 Subject: [PATCH 01/67] add wrangle crop button to browse crops page --- app/views/crops/index.html.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/crops/index.html.haml b/app/views/crops/index.html.haml index 1b5663c25..9674cb360 100644 --- a/app/views/crops/index.html.haml +++ b/app/views/crops/index.html.haml @@ -1,5 +1,6 @@ - content_for :title, "Crops" - +- if current_member.has_role?(:crop_wrangler) + = link_to 'Wrangle Crops', wrangle_crops_path, :class => 'btn btn-primary' %p #{ENV['GROWSTUFF_SITE_NAME']} tracks who's growing what, where. View any crop page to see which of our members have planted it and find From 760e5ca74eb8d1e211bac919fabbc179ba497499 Mon Sep 17 00:00:00 2001 From: Robert Landreaux Date: Sat, 17 Jan 2015 12:21:01 -0500 Subject: [PATCH 02/67] remove failing line and add '- if can? :wrangle, Crop' --- app/views/crops/index.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/crops/index.html.haml b/app/views/crops/index.html.haml index 9674cb360..f6915d9d1 100644 --- a/app/views/crops/index.html.haml +++ b/app/views/crops/index.html.haml @@ -1,5 +1,5 @@ - content_for :title, "Crops" -- if current_member.has_role?(:crop_wrangler) + - if can? :wrangle, Crop = link_to 'Wrangle Crops', wrangle_crops_path, :class => 'btn btn-primary' %p #{ENV['GROWSTUFF_SITE_NAME']} tracks who's growing what, where. From e4072fb395c2d32d2abe695e18fdaef16f9c571e Mon Sep 17 00:00:00 2001 From: Robert Landreaux Date: Sun, 18 Jan 2015 23:25:38 -0500 Subject: [PATCH 03/67] write 'crop_wrangling_button_spec.rb', fix previous issue --- CONTRIBUTORS.md | 2 +- .../crops/crop_wrangling_button_spec.rb | 56 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 spec/features/crops/crop_wrangling_button_spec.rb diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index bddcb3095..60a69a272 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -52,4 +52,4 @@ submit the change with your pull request. - Kevin Yang / [kevieyang](https://github.com/kevieyang) - Justin Hamman / [juzham](https://github.com/juzham) - Rocky Jaiswal / [rocky-jaiswal](https://github.com/rocky-jaiswal) - +- Robert Landreaux / [robertlandreaux](https://github.com/robertlandreaux) diff --git a/spec/features/crops/crop_wrangling_button_spec.rb b/spec/features/crops/crop_wrangling_button_spec.rb new file mode 100644 index 000000000..87c4f3f95 --- /dev/null +++ b/spec/features/crops/crop_wrangling_button_spec.rb @@ -0,0 +1,56 @@ +require 'rails_helper' + +feature "crop wrangling button" do + + let(:crop_wrangler_member) { FactoryGirl.create(:crop_wrangler_member) } + + context "crop wrangling button" do + + background do + login_as(:crop_wrangler_member) + end + + background do + visit crops_path + end + + scenario "has a link to crop wrangling page" do + expect(page).to have_link "Wrangle Crops", wrangle_crops_path + end + + end + + let(:admin_member) { FactoryGirl.create(:admin_member) } + + context "crop wrangling button" do + + background do + login_as(:admin_member) + end + + background do + visit crops_path + end + + scenario "has a link to crop wrangling page" do + expect(page).to have_link "Wrangle Crops", wrangle_crops_path + end + + end + + let(:member) { FactoryGirl.create(:member) } + + context "crop wrangling button" do + + background do + login_as(:member) + end + + background do + visit crops_path + end + + scenario "has no link to crop wrangling page" + expect(page).to have_no_link "Wrangle Crops", wrangle_crops_path + end + end From 1a5056632879e8c8424ca084f67d57f665603088 Mon Sep 17 00:00:00 2001 From: Robert Landreaux Date: Mon, 19 Jan 2015 11:14:36 -0500 Subject: [PATCH 04/67] modify test, still needs work --- .../crops/crop_wrangling_button_spec.rb | 31 +++---------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/spec/features/crops/crop_wrangling_button_spec.rb b/spec/features/crops/crop_wrangling_button_spec.rb index 87c4f3f95..184d2fbd8 100644 --- a/spec/features/crops/crop_wrangling_button_spec.rb +++ b/spec/features/crops/crop_wrangling_button_spec.rb @@ -2,33 +2,12 @@ require 'rails_helper' feature "crop wrangling button" do - let(:crop_wrangler_member) { FactoryGirl.create(:crop_wrangler_member) } + let(:crop_wrangling_member) { FactoryGirl.create(:crop_wrangler) } context "crop wrangling button" do background do - login_as(:crop_wrangler_member) - end - - background do - visit crops_path - end - - scenario "has a link to crop wrangling page" do - expect(page).to have_link "Wrangle Crops", wrangle_crops_path - end - - end - - let(:admin_member) { FactoryGirl.create(:admin_member) } - - context "crop wrangling button" do - - background do - login_as(:admin_member) - end - - background do + login_as(:crop_wrangler) visit crops_path end @@ -44,13 +23,11 @@ feature "crop wrangling button" do background do login_as(:member) - end - - background do visit crops_path end - scenario "has no link to crop wrangling page" + scenario "has no link to crop wrangling page" do expect(page).to have_no_link "Wrangle Crops", wrangle_crops_path end end + end From f404d54d02bf6a507927cebfb164011940f7e542 Mon Sep 17 00:00:00 2001 From: Robert Landreaux Date: Tue, 20 Jan 2015 12:08:58 -0500 Subject: [PATCH 05/67] update crop_wrangling_button_spec.rb --- app/views/crops/index.html.haml | 3 ++- spec/features/crops/crop_wrangling_button_spec.rb | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/views/crops/index.html.haml b/app/views/crops/index.html.haml index f6915d9d1..158bf965b 100644 --- a/app/views/crops/index.html.haml +++ b/app/views/crops/index.html.haml @@ -1,6 +1,7 @@ - content_for :title, "Crops" + - if can? :wrangle, Crop - = link_to 'Wrangle Crops', wrangle_crops_path, :class => 'btn btn-primary' + = link_to 'Wrangle Crops', wrangle_crops_path, :class => 'btn btn-primary' %p #{ENV['GROWSTUFF_SITE_NAME']} tracks who's growing what, where. View any crop page to see which of our members have planted it and find diff --git a/spec/features/crops/crop_wrangling_button_spec.rb b/spec/features/crops/crop_wrangling_button_spec.rb index 184d2fbd8..3acbedad4 100644 --- a/spec/features/crops/crop_wrangling_button_spec.rb +++ b/spec/features/crops/crop_wrangling_button_spec.rb @@ -12,7 +12,7 @@ feature "crop wrangling button" do end scenario "has a link to crop wrangling page" do - expect(page).to have_link "Wrangle Crops", wrangle_crops_path + expect(page).to have_link "Wrangle Crops", :href => wrangle_crops_path end end @@ -27,7 +27,7 @@ feature "crop wrangling button" do end scenario "has no link to crop wrangling page" do - expect(page).to have_no_link "Wrangle Crops", wrangle_crops_path + expect(page).to have_no_link "Wrangle Crops", :href => wrangle_crops_path end end end From 9a18b4b62b62d8a92cf6986aed63390ecddeff88 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Sat, 24 Jan 2015 11:31:35 +0000 Subject: [PATCH 06/67] Add new properties to seeds Added days_until_maturity, gmo, organic and heirloom properties; added validation and tests for the last three. --- app/models/seed.rb | 26 ++++ .../20150124110540_add_properties_to_seeds.rb | 8 ++ db/schema.rb | 117 +++++++++--------- spec/factories/seeds.rb | 3 + spec/models/seed_spec.rb | 43 +++++++ 5 files changed, 141 insertions(+), 56 deletions(-) create mode 100644 db/migrate/20150124110540_add_properties_to_seeds.rb diff --git a/app/models/seed.rb b/app/models/seed.rb index c7128da72..49013918f 100644 --- a/app/models/seed.rb +++ b/app/models/seed.rb @@ -20,6 +20,32 @@ class Seed < ActiveRecord::Base :allow_nil => false, :allow_blank => false + ORGANIC_VALUES = [ + 'certified organic', + 'non-certified organic', + 'conventional/non-organic', + 'unknown'] + validates :organic, :inclusion => { :in => ORGANIC_VALUES, + :message => "You must say whether the seeds are organic or not, or that you don't know" }, + :allow_nil => false, + :allow_blank => false + + GMO_VALUES = [ + 'certified GMO-free', + 'non-certified GMO-free', + 'GMO', + 'unknown'] + validates :gmo, :inclusion => { :in => GMO_VALUES, + :message => "You must say whether the seeds are genetically modified or not, or that you don't know" }, + :allow_nil => false, + :allow_blank => false + + HEIRLOOM_VALUES = %w(heirloom hybrid unknown) + validates :heirloom, :inclusion => { :in => HEIRLOOM_VALUES, + :message => "You must say whether the seeds are heirloom, hybrid, or unknown" }, + :allow_nil => false, + :allow_blank => false + def tradable? if self.tradable_to == 'nowhere' return false diff --git a/db/migrate/20150124110540_add_properties_to_seeds.rb b/db/migrate/20150124110540_add_properties_to_seeds.rb new file mode 100644 index 000000000..46cc67461 --- /dev/null +++ b/db/migrate/20150124110540_add_properties_to_seeds.rb @@ -0,0 +1,8 @@ +class AddPropertiesToSeeds < ActiveRecord::Migration + def change + add_column :seeds, :days_until_maturity, :integer + add_column :seeds, :organic, :text, :default => 'unknown' + add_column :seeds, :gmo, :text, :default => 'unknown' + add_column :seeds, :heirloom, :text, :default => 'unknown' + end +end diff --git a/db/schema.rb b/db/schema.rb index 9c4137f40..8ab4d579d 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20141119130555) do +ActiveRecord::Schema.define(version: 20150124110540) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -20,24 +20,24 @@ ActiveRecord::Schema.define(version: 20141119130555) do t.string "name", null: false t.boolean "is_paid" t.boolean "is_permanent_paid" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "accounts", force: true do |t| t.integer "member_id", null: false t.integer "account_type_id" t.datetime "paid_until" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "alternate_names", force: true do |t| t.string "name", null: false t.integer "crop_id", null: false t.integer "creator_id", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "authentications", force: true do |t| @@ -46,8 +46,8 @@ ActiveRecord::Schema.define(version: 20141119130555) do t.string "uid" t.string "token" t.string "secret" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "name" end @@ -57,15 +57,15 @@ ActiveRecord::Schema.define(version: 20141119130555) do t.integer "post_id", null: false t.integer "author_id", null: false t.text "body", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "crops", force: true do |t| t.string "name", null: false t.string "en_wikipedia_url" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "slug" t.integer "parent_id" t.integer "plantings_count", default: 0 @@ -86,16 +86,16 @@ ActiveRecord::Schema.define(version: 20141119130555) do create_table "follows", force: true do |t| t.integer "follower_id" t.integer "followed_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "forums", force: true do |t| t.string "name", null: false t.text "description", null: false t.integer "owner_id", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "slug" end @@ -105,8 +105,8 @@ ActiveRecord::Schema.define(version: 20141119130555) do t.string "name", null: false t.integer "owner_id" t.string "slug", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.text "description" t.boolean "active", default: true t.string "location" @@ -116,7 +116,7 @@ ActiveRecord::Schema.define(version: 20141119130555) do t.string "area_unit" end - add_index "gardens", ["owner_id"], name: "index_gardens_on_owner_id", using: :btree + add_index "gardens", ["owner_id"], name: "index_gardens_on_user_id", using: :btree add_index "gardens", ["slug"], name: "index_gardens_on_slug", unique: true, using: :btree create_table "harvests", force: true do |t| @@ -126,8 +126,8 @@ ActiveRecord::Schema.define(version: 20141119130555) do t.decimal "quantity" t.string "unit" t.text "description" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "slug" t.decimal "weight_quantity" t.string "weight_unit" @@ -159,8 +159,8 @@ ActiveRecord::Schema.define(version: 20141119130555) do t.integer "failed_attempts", default: 0 t.string "unlock_token" t.datetime "locked_at" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "login_name" t.string "slug" t.boolean "tos_agreement" @@ -175,11 +175,11 @@ ActiveRecord::Schema.define(version: 20141119130555) do t.boolean "send_planting_reminder", default: true end - add_index "members", ["confirmation_token"], name: "index_members_on_confirmation_token", unique: true, using: :btree - add_index "members", ["email"], name: "index_members_on_email", unique: true, using: :btree - add_index "members", ["reset_password_token"], name: "index_members_on_reset_password_token", unique: true, using: :btree - add_index "members", ["slug"], name: "index_members_on_slug", unique: true, using: :btree - add_index "members", ["unlock_token"], name: "index_members_on_unlock_token", unique: true, using: :btree + add_index "members", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree + add_index "members", ["email"], name: "index_users_on_email", unique: true, using: :btree + add_index "members", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree + add_index "members", ["slug"], name: "index_users_on_slug", unique: true, using: :btree + add_index "members", ["unlock_token"], name: "index_users_on_unlock_token", unique: true, using: :btree create_table "members_roles", id: false, force: true do |t| t.integer "member_id" @@ -193,8 +193,8 @@ ActiveRecord::Schema.define(version: 20141119130555) do t.text "body" t.boolean "read", default: false t.integer "post_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "order_items", force: true do |t| @@ -202,13 +202,13 @@ ActiveRecord::Schema.define(version: 20141119130555) do t.integer "product_id" t.integer "price" t.integer "quantity" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "orders", force: true do |t| - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.datetime "completed_at" t.integer "member_id" t.string "paypal_express_token" @@ -225,8 +225,8 @@ ActiveRecord::Schema.define(version: 20141119130555) do t.integer "owner_id", null: false t.string "thumbnail_url", null: false t.string "fullsize_url", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "title", null: false t.string "license_name", null: false t.string "license_url" @@ -241,8 +241,8 @@ ActiveRecord::Schema.define(version: 20141119130555) do create_table "plant_parts", force: true do |t| t.string "name" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "slug" end @@ -252,8 +252,8 @@ ActiveRecord::Schema.define(version: 20141119130555) do t.date "planted_at" t.integer "quantity" t.text "description" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "slug" t.string "sunniness" t.string "planted_from" @@ -268,21 +268,22 @@ ActiveRecord::Schema.define(version: 20141119130555) do t.integer "author_id", null: false t.string "subject", null: false t.text "body", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "slug" t.integer "forum_id" + t.integer "parent_id" end - add_index "posts", ["created_at", "author_id"], name: "index_posts_on_created_at_and_author_id", using: :btree - add_index "posts", ["slug"], name: "index_posts_on_slug", unique: true, using: :btree + add_index "posts", ["created_at", "author_id"], name: "index_updates_on_created_at_and_user_id", using: :btree + add_index "posts", ["slug"], name: "index_updates_on_slug", unique: true, using: :btree create_table "products", force: true do |t| t.string "name", null: false t.text "description", null: false t.integer "min_price", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "account_type_id" t.integer "paid_months" t.integer "recommended_price" @@ -291,8 +292,8 @@ ActiveRecord::Schema.define(version: 20141119130555) do create_table "roles", force: true do |t| t.string "name", null: false t.text "description" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "slug" end @@ -301,21 +302,25 @@ ActiveRecord::Schema.define(version: 20141119130555) do create_table "scientific_names", force: true do |t| t.string "scientific_name", null: false t.integer "crop_id", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "creator_id" end create_table "seeds", force: true do |t| - t.integer "owner_id", null: false - t.integer "crop_id", null: false + t.integer "owner_id", null: false + t.integer "crop_id", null: false t.text "description" t.integer "quantity" t.date "plant_before" - t.datetime "created_at" - t.datetime "updated_at" - t.string "tradable_to", default: "nowhere" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "tradable_to", default: "nowhere" t.string "slug" + t.integer "days_until_maturity" + t.text "organic", default: "unknown" + t.text "gmo", default: "unknown" + t.text "heirloom", default: "unknown" end add_index "seeds", ["slug"], name: "index_seeds_on_slug", unique: true, using: :btree diff --git a/spec/factories/seeds.rb b/spec/factories/seeds.rb index bd5944d1b..227a83a86 100644 --- a/spec/factories/seeds.rb +++ b/spec/factories/seeds.rb @@ -8,6 +8,9 @@ FactoryGirl.define do quantity 1 plant_before "2013-07-15" tradable_to 'nowhere' + organic 'unknown' + gmo 'unknown' + heirloom 'unknown' factory :tradable_seed do tradable_to "locally" diff --git a/spec/models/seed_spec.rb b/spec/models/seed_spec.rb index cfd73bf04..747dbee71 100644 --- a/spec/models/seed_spec.rb +++ b/spec/models/seed_spec.rb @@ -88,6 +88,49 @@ describe Seed do end end + context 'organic, gmo, heirloom' do + it 'all valid organic values should work' do + ['certified organic', 'non-certified organic', + 'conventional/non-organic', 'unknown'].each do |t| + @seed = FactoryGirl.build(:seed, :organic => t) + @seed.should be_valid + end + end + + it 'all valid GMO values should work' do + ['certified GMO-free', 'non-certified GMO-free', + 'GMO', 'unknown'].each do |t| + @seed = FactoryGirl.build(:seed, :gmo => t) + @seed.should be_valid + end + end + + it 'all valid heirloom values should work' do + %w(heirloom hybrid unknown).each do |t| + @seed = FactoryGirl.build(:seed, :heirloom => t) + @seed.should be_valid + end + end + + it 'should refuse invalid organic/GMO/heirloom values' do + [:organic, :gmo, :heirloom].each do |field| + @seed = FactoryGirl.build(:seed, field => 'not valid') + @seed.should_not be_valid + @seed.errors[field].should_not be_empty + end + end + + it 'should not allow nil or blank values' do + [:organic, :gmo, :heirloom].each do |field| + @seed = FactoryGirl.build(:seed, field => nil) + @seed.should_not be_valid + @seed = FactoryGirl.build(:seed, field => '') + @seed.should_not be_valid + end + end + end + + context 'interesting' do it 'lists interesting seeds' do From 038192095da6e8954c3e0ddcf990d4fb6b356ef5 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Sat, 24 Jan 2015 11:39:50 +0000 Subject: [PATCH 07/67] Validate all numeric fields as being >= 0. --- app/models/garden.rb | 4 +++- app/models/harvest.rb | 4 +++- app/models/planting.rb | 4 +++- app/models/product.rb | 7 +++++-- app/models/seed.rb | 9 ++++++++- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/app/models/garden.rb b/app/models/garden.rb index 61e51d97d..52250c4c7 100644 --- a/app/models/garden.rb +++ b/app/models/garden.rb @@ -23,7 +23,9 @@ class Garden < ActiveRecord::Base } validates :area, - :numericality => { :only_integer => false, :greater_than_or_equal_to => 0 }, + :numericality => { + :only_integer => false, + :greater_than_or_equal_to => 0 }, :allow_nil => true AREA_UNITS_VALUES = { diff --git a/app/models/harvest.rb b/app/models/harvest.rb index 4e43c6ee7..e4abe7f70 100644 --- a/app/models/harvest.rb +++ b/app/models/harvest.rb @@ -23,7 +23,9 @@ class Harvest < ActiveRecord::Base validates :crop, :presence => {:message => "must be present and exist in our database"} validates :quantity, - :numericality => { :only_integer => false }, + :numericality => { + :only_integer => false, + :greater_than_or_equal_to => 0 }, :allow_nil => true UNITS_VALUES = { diff --git a/app/models/planting.rb b/app/models/planting.rb index e9c11368b..592ef1681 100644 --- a/app/models/planting.rb +++ b/app/models/planting.rb @@ -33,7 +33,9 @@ class Planting < ActiveRecord::Base validates :crop_id, :presence => {:message => "must be present and exist in our database"} validates :quantity, - :numericality => { :only_integer => true }, + :numericality => { + :only_integer => true, + :greater_than_or_equal_to => 0 }, :allow_nil => true SUNNINESS_VALUES = %w(sun semi-shade shade) diff --git a/app/models/product.rb b/app/models/product.rb index 876207f47..68d483665 100644 --- a/app/models/product.rb +++ b/app/models/product.rb @@ -2,8 +2,11 @@ class Product < ActiveRecord::Base has_and_belongs_to_many :orders belongs_to :account_type - validates :paid_months, :numericality => { :only_integer => true, - :allow_nil => true } + validates :paid_months, + :numericality => { + :only_integer => true, + :greater_than_or_equal_to => 0 }, + :allow_nil => true def to_s name diff --git a/app/models/seed.rb b/app/models/seed.rb index 49013918f..96b9fa5a2 100644 --- a/app/models/seed.rb +++ b/app/models/seed.rb @@ -9,7 +9,14 @@ class Seed < ActiveRecord::Base validates :crop, :presence => {:message => "must be present and exist in our database"} validates :quantity, - :numericality => { :only_integer => true }, + :numericality => { + :only_integer => true, + :greater_than_or_equal_to => 0 }, + :allow_nil => true + validates :days_until_maturity, + :numericality => { + :only_integer => true, + :greater_than_or_equal_to => 0 }, :allow_nil => true scope :tradable, -> { where("tradable_to != 'nowhere'") } From b56237115e454a17ca8c2647402948d87aabd90e Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Sat, 24 Jan 2015 12:01:11 +0000 Subject: [PATCH 08/67] Add form and controller for new seed properties --- app/controllers/seeds_controller.rb | 5 +++-- app/views/seeds/_form.html.haml | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/app/controllers/seeds_controller.rb b/app/controllers/seeds_controller.rb index ac5dfb0c3..a1d6de8e3 100644 --- a/app/controllers/seeds_controller.rb +++ b/app/controllers/seeds_controller.rb @@ -110,7 +110,8 @@ class SeedsController < ApplicationController private def seed_params - params.require(:seed).permit(:owner_id, :crop_id, :description, :quantity, :plant_before, - :tradable_to, :slug) + params.require(:seed).permit( + :owner_id, :crop_id, :description, :quantity, :plant_before, + :days_until_maturity, :organic, :gmo, :heirloom, :tradable_to, :slug) end end diff --git a/app/views/seeds/_form.html.haml b/app/views/seeds/_form.html.haml index 642a5de01..c0b09c3bc 100644 --- a/app/views/seeds/_form.html.haml +++ b/app/views/seeds/_form.html.haml @@ -21,6 +21,22 @@ = f.label :plant_before, 'Plant before:', :class => 'control-label col-md-2' .col-md-2 = f.text_field :plant_before, :class => 'add-datepicker form-control', :value => @seed.plant_before ? @seed.plant_before.to_s(:ymd) : '' + .form-group + = f.label :days_until_maturity, 'Days until maturity:', :class => 'control-label col-md-2' + .col-md-2 + = f.number_field :days_until_maturity, :class => 'form-control' + .form-group + = f.label :organic, 'Organic?', :class => 'control-label col-md-2' + .col-md-8 + = f.select(:organic, Seed::ORGANIC_VALUES, {}, :class => 'form-control', :default => 'unknown') + .form-group + = f.label :gmo, 'GMO?', :class => 'control-label col-md-2' + .col-md-8 + = f.select(:gmo, Seed::GMO_VALUES, {}, :class => 'form-control', :default => 'unknown') + .form-group + = f.label :heirloom, 'Heirloom?', :class => 'control-label col-md-2' + .col-md-8 + = f.select(:heirloom, Seed::HEIRLOOM_VALUES, {}, :class => 'form-control', :default => 'unknown') .form-group = f.label :description, 'Description:', :class => 'control-label col-md-2' .col-md-8 From 2442539e1bc8339ae75d7b6f6a04f703eb791d28 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Sat, 24 Jan 2015 12:08:02 +0000 Subject: [PATCH 09/67] Allow feature tests and unicorn to run at the same time --- spec/rails_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 9618ca895..784cfba6f 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -25,7 +25,7 @@ require 'capybara' require 'capybara/poltergeist' Capybara.javascript_driver = :poltergeist Capybara.app_host = 'http://localhost' -Capybara.server_port = 8080 +Capybara.server_port = 8081 include Warden::Test::Helpers From 58940a67655613b8a95773d6fee2ae22f661818d Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Sat, 24 Jan 2015 12:10:46 +0000 Subject: [PATCH 10/67] Add new seed properties to feature. --- spec/features/seeds/adding_seeds_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/features/seeds/adding_seeds_spec.rb b/spec/features/seeds/adding_seeds_spec.rb index 668771850..cda26603a 100644 --- a/spec/features/seeds/adding_seeds_spec.rb +++ b/spec/features/seeds/adding_seeds_spec.rb @@ -17,6 +17,10 @@ feature "Harvesting a crop", :js => true do within "form#new_seed" do fill_in "Quantity:", :with => 42 fill_in "Plant before:", :with => "2014-06-15" + fill_in "Days until maturity:", :with => 999 + select "certified organic", :from => "Organic?" + select "non-certified GMO-free", :from => "GMO?" + select "heirloom", :from => "Heirloom?" fill_in "Description", :with => "It's killer." select "internationally", :from => "Will trade:" click_button "Save" From 334b5bf63f5315bf1b92714e3fe63a0bed249f0c Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Sat, 24 Jan 2015 12:24:11 +0000 Subject: [PATCH 11/67] Test new seed properties on detail page --- spec/features/seeds/adding_seeds_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/features/seeds/adding_seeds_spec.rb b/spec/features/seeds/adding_seeds_spec.rb index cda26603a..65bc3fcdd 100644 --- a/spec/features/seeds/adding_seeds_spec.rb +++ b/spec/features/seeds/adding_seeds_spec.rb @@ -27,6 +27,12 @@ feature "Harvesting a crop", :js => true do end expect(page).to have_content "Successfully added maize seed to your stash" + expect(page).to have_content "Quantity: 42" + expect(page).to have_content "Days until maturity: 999" + expect(page).to have_content "certified organic" + expect(page).to have_content "non-certified GMO-free" + expect(page).to have_content "Heirloom? heirloom" + expect(page).to have_content "It's killer." end scenario "Adding a seed from crop page" do From 329e147add5dae6a5ea2f548904b8d4c5138369c Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Sat, 24 Jan 2015 12:34:14 +0000 Subject: [PATCH 12/67] Show new seed props in detail page --- app/views/seeds/show.html.haml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/views/seeds/show.html.haml b/app/views/seeds/show.html.haml index 7db91c1a6..dfc47108c 100644 --- a/app/views/seeds/show.html.haml +++ b/app/views/seeds/show.html.haml @@ -13,6 +13,18 @@ %p %b Plant before: = @seed.plant_before.to_s + %p + %b Days until maturity: + = @seed.days_until_maturity.to_s + %p + %b Organic? + = @seed.organic + %p + %b GMO? + = @seed.gmo + %p + %b Heirloom? + = @seed.heirloom %p %b Will trade: = @seed.tradable_to From 233f9dfd880a840703d8f8d15021e6b59b90c976 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Mon, 26 Jan 2015 19:18:23 +0000 Subject: [PATCH 13/67] Split "days until maturity" into min and max fields. --- app/controllers/seeds_controller.rb | 3 ++- app/models/seed.rb | 7 ++++++- .../seeds/_days_until_maturity.html.haml | 9 +++++++++ app/views/seeds/_form.html.haml | 7 +++++-- app/views/seeds/show.html.haml | 2 +- .../20150124110540_add_properties_to_seeds.rb | 3 ++- db/schema.rb | 19 ++++++++++--------- spec/features/seeds/adding_seeds_spec.rb | 3 ++- 8 files changed, 37 insertions(+), 16 deletions(-) create mode 100644 app/views/seeds/_days_until_maturity.html.haml diff --git a/app/controllers/seeds_controller.rb b/app/controllers/seeds_controller.rb index a1d6de8e3..a2e79afaf 100644 --- a/app/controllers/seeds_controller.rb +++ b/app/controllers/seeds_controller.rb @@ -112,6 +112,7 @@ class SeedsController < ApplicationController def seed_params params.require(:seed).permit( :owner_id, :crop_id, :description, :quantity, :plant_before, - :days_until_maturity, :organic, :gmo, :heirloom, :tradable_to, :slug) + :days_until_maturity_min, :days_until_maturity_max, :organic, :gmo, + :heirloom, :tradable_to, :slug) end end diff --git a/app/models/seed.rb b/app/models/seed.rb index 96b9fa5a2..cae7402d9 100644 --- a/app/models/seed.rb +++ b/app/models/seed.rb @@ -13,7 +13,12 @@ class Seed < ActiveRecord::Base :only_integer => true, :greater_than_or_equal_to => 0 }, :allow_nil => true - validates :days_until_maturity, + validates :days_until_maturity_min, + :numericality => { + :only_integer => true, + :greater_than_or_equal_to => 0 }, + :allow_nil => true + validates :days_until_maturity_max, :numericality => { :only_integer => true, :greater_than_or_equal_to => 0 }, diff --git a/app/views/seeds/_days_until_maturity.html.haml b/app/views/seeds/_days_until_maturity.html.haml new file mode 100644 index 000000000..b8db4a203 --- /dev/null +++ b/app/views/seeds/_days_until_maturity.html.haml @@ -0,0 +1,9 @@ +- if seed.days_until_maturity_min.blank? + - if seed.days_until_maturity_max.blank? + unknown + - else + = seed.days_until_maturity_max.to_s +- elsif seed.days_until_maturity_max.blank? + = seed.days_until_maturity_min.to_s +- else + != "#{seed.days_until_maturity_min}–#{seed.days_until_maturity_max}" diff --git a/app/views/seeds/_form.html.haml b/app/views/seeds/_form.html.haml index c0b09c3bc..9472e2799 100644 --- a/app/views/seeds/_form.html.haml +++ b/app/views/seeds/_form.html.haml @@ -22,9 +22,12 @@ .col-md-2 = f.text_field :plant_before, :class => 'add-datepicker form-control', :value => @seed.plant_before ? @seed.plant_before.to_s(:ymd) : '' .form-group - = f.label :days_until_maturity, 'Days until maturity:', :class => 'control-label col-md-2' + = f.label :days_until_maturity_min, 'Days until maturity, min:', :class => 'control-label col-md-2' .col-md-2 - = f.number_field :days_until_maturity, :class => 'form-control' + = f.number_field :days_until_maturity_min, :class => 'form-control' + = f.label :days_until_maturity_max, 'Days until maturity, max:', :class => 'control-label col-md-2' + .col-md-2 + = f.number_field :days_until_maturity_max, :class => 'form-control' .form-group = f.label :organic, 'Organic?', :class => 'control-label col-md-2' .col-md-8 diff --git a/app/views/seeds/show.html.haml b/app/views/seeds/show.html.haml index dfc47108c..c2f3399ea 100644 --- a/app/views/seeds/show.html.haml +++ b/app/views/seeds/show.html.haml @@ -15,7 +15,7 @@ = @seed.plant_before.to_s %p %b Days until maturity: - = @seed.days_until_maturity.to_s + = render :partial => 'days_until_maturity', :locals => { :seed => @seed } %p %b Organic? = @seed.organic diff --git a/db/migrate/20150124110540_add_properties_to_seeds.rb b/db/migrate/20150124110540_add_properties_to_seeds.rb index 46cc67461..e2fa64fe7 100644 --- a/db/migrate/20150124110540_add_properties_to_seeds.rb +++ b/db/migrate/20150124110540_add_properties_to_seeds.rb @@ -1,6 +1,7 @@ class AddPropertiesToSeeds < ActiveRecord::Migration def change - add_column :seeds, :days_until_maturity, :integer + add_column :seeds, :days_until_maturity_min, :integer + add_column :seeds, :days_until_maturity_max, :integer add_column :seeds, :organic, :text, :default => 'unknown' add_column :seeds, :gmo, :text, :default => 'unknown' add_column :seeds, :heirloom, :text, :default => 'unknown' diff --git a/db/schema.rb b/db/schema.rb index 8ab4d579d..365c9d151 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -308,19 +308,20 @@ ActiveRecord::Schema.define(version: 20150124110540) do end create_table "seeds", force: true do |t| - t.integer "owner_id", null: false - t.integer "crop_id", null: false + t.integer "owner_id", null: false + t.integer "crop_id", null: false t.text "description" t.integer "quantity" t.date "plant_before" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "tradable_to", default: "nowhere" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "tradable_to", default: "nowhere" t.string "slug" - t.integer "days_until_maturity" - t.text "organic", default: "unknown" - t.text "gmo", default: "unknown" - t.text "heirloom", default: "unknown" + t.integer "days_until_maturity_min" + t.integer "days_until_maturity_max" + t.text "organic", default: "unknown" + t.text "gmo", default: "unknown" + t.text "heirloom", default: "unknown" end add_index "seeds", ["slug"], name: "index_seeds_on_slug", unique: true, using: :btree diff --git a/spec/features/seeds/adding_seeds_spec.rb b/spec/features/seeds/adding_seeds_spec.rb index 65bc3fcdd..e69b380d6 100644 --- a/spec/features/seeds/adding_seeds_spec.rb +++ b/spec/features/seeds/adding_seeds_spec.rb @@ -17,7 +17,8 @@ feature "Harvesting a crop", :js => true do within "form#new_seed" do fill_in "Quantity:", :with => 42 fill_in "Plant before:", :with => "2014-06-15" - fill_in "Days until maturity:", :with => 999 + fill_in "Days until maturity, min:", :with => 999 + fill_in "Days until maturity, max:", :with => 1999 select "certified organic", :from => "Organic?" select "non-certified GMO-free", :from => "GMO?" select "heirloom", :from => "Heirloom?" From 22e0379769ef64d05d57d00455153193d6cc76de Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Sat, 31 Jan 2015 09:54:59 +1100 Subject: [PATCH 14/67] give crops a requester --- app/models/crop.rb | 1 + ...50130224814_add_requester_and_approved_to_crops.rb | 7 +++++++ db/schema.rb | 11 +++++++---- 3 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20150130224814_add_requester_and_approved_to_crops.rb diff --git a/app/models/crop.rb b/app/models/crop.rb index 0a7d8d442..dff06f498 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -14,6 +14,7 @@ class Crop < ActiveRecord::Base has_many :harvests has_many :plant_parts, -> { uniq }, :through => :harvests belongs_to :creator, :class_name => 'Member' + belongs_to :creator, :class_name => 'Member' belongs_to :parent, :class_name => 'Crop' has_many :varieties, :class_name => 'Crop', :foreign_key => 'parent_id' diff --git a/db/migrate/20150130224814_add_requester_and_approved_to_crops.rb b/db/migrate/20150130224814_add_requester_and_approved_to_crops.rb new file mode 100644 index 000000000..e9295f7f9 --- /dev/null +++ b/db/migrate/20150130224814_add_requester_and_approved_to_crops.rb @@ -0,0 +1,7 @@ +class AddRequesterAndApprovedToCrops < ActiveRecord::Migration + def change + add_column :crops, :requester_id, :integer + add_column :crops, :approved, :boolean, default: true + add_index :crops, :requester_id + end +end diff --git a/db/schema.rb b/db/schema.rb index 9e593a422..73e87cf3f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150127043022) do +ActiveRecord::Schema.define(version: 20150130224814) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -62,17 +62,20 @@ ActiveRecord::Schema.define(version: 20150127043022) do end create_table "crops", force: true do |t| - t.string "name", null: false + t.string "name", null: false t.string "en_wikipedia_url" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "slug" t.integer "parent_id" t.integer "plantings_count", default: 0 t.integer "creator_id" + t.integer "requester_id" + t.boolean "approved", default: true end add_index "crops", ["name"], name: "index_crops_on_name", using: :btree + add_index "crops", ["requester_id"], name: "index_crops_on_requester_id", using: :btree add_index "crops", ["slug"], name: "index_crops_on_slug", unique: true, using: :btree create_table "crops_posts", id: false, force: true do |t| From 28d29291a7cc75b328faf4708a1aa6720fdc1f2f Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Sat, 31 Jan 2015 10:03:44 +1100 Subject: [PATCH 15/67] any member can create a crop at least provisionally --- app/controllers/crops_controller.rb | 8 +++++++- app/models/ability.rb | 3 +++ app/models/crop.rb | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index 2b5e2f22e..89c0c0ede 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -101,9 +101,15 @@ class CropsController < ApplicationController # POST /crops # POST /crops.json def create - params[:crop][:creator_id] = current_member.id @crop = Crop.new(crop_params) + if current_member.has_role? :crop_wrangler + @crop.creator = current_member + else + @crop.requester = current_member + @crop.approved = false + end + respond_to do |format| if @crop.save format.html { redirect_to @crop, notice: 'Crop was successfully created.' } diff --git a/app/models/ability.rb b/app/models/ability.rb index a7b77b623..51c03e048 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -45,6 +45,9 @@ class Ability can :manage, AlternateName end + # any member can create a crop provisionally + can :create, Crop + # can create & destroy their own authentications against other sites. can :create, Authentication can :destroy, Authentication, :member_id => member.id diff --git a/app/models/crop.rb b/app/models/crop.rb index dff06f498..4c8f2dd06 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -14,7 +14,7 @@ class Crop < ActiveRecord::Base has_many :harvests has_many :plant_parts, -> { uniq }, :through => :harvests belongs_to :creator, :class_name => 'Member' - belongs_to :creator, :class_name => 'Member' + belongs_to :requester, :class_name => 'Member' belongs_to :parent, :class_name => 'Crop' has_many :varieties, :class_name => 'Crop', :foreign_key => 'parent_id' From 41db12d8d79fdd8d220241d021aa7066e9bdd547 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Sat, 31 Jan 2015 10:36:02 +1100 Subject: [PATCH 16/67] pending approval crops appear on crops wrangle page --- app/controllers/crops_controller.rb | 3 ++- app/models/crop.rb | 1 + app/views/crops/wrangle.html.haml | 34 ++++++++++++++++++++++++----- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index 89c0c0ede..aae0cc928 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -32,7 +32,8 @@ class CropsController < ApplicationController # GET /crops/wrangle def wrangle - @crops = Crop.recent.paginate(:page => params[:page]) + @recent_crops = Crop.recent.paginate(:page => params[:page]) + @pending_approval = Crop.pending_approval @crop_wranglers = Role.crop_wranglers respond_to do |format| format.html diff --git a/app/models/crop.rb b/app/models/crop.rb index 4c8f2dd06..5a63b31d2 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -26,6 +26,7 @@ class Crop < ActiveRecord::Base scope :toplevel, -> { where(:parent_id => nil) } scope :popular, -> { reorder("plantings_count desc, lower(name) asc") } scope :randomized, -> { reorder('random()') } # ok on sqlite and psql, but not on mysql + scope :pending_approval, -> { where(:approved => false) } validates :en_wikipedia_url, :format => { diff --git a/app/views/crops/wrangle.html.haml b/app/views/crops/wrangle.html.haml index b26f29fc9..07091c595 100644 --- a/app/views/crops/wrangle.html.haml +++ b/app/views/crops/wrangle.html.haml @@ -15,11 +15,35 @@ %li.crop_wrangler = link_to crop_wrangler.login_name, crop_wrangler +%h2 Requested crops + +%table.table.table-striped + %thead + %tr + %th System name + %th English Wikipedia URL + %th Scientific names + %th Requested by + %th When requested + %tbody + - @pending_approval.each do |c| + %tr + %td= link_to c.name, c + %td= link_to c.en_wikipedia_url, c.en_wikipedia_url + %td + - c.scientific_names.each do |s| + = link_to s.scientific_name, s + %br/ + %td= link_to c.requester, c.requester + %td + = distance_of_time_in_words(c.created_at, Time.zone.now) + ago. + %h2 Recently added crops %div.pagination - = page_entries_info @crops, :model => "crops" - = will_paginate @crops + = page_entries_info @recent_crops, :model => "crops" + = will_paginate @recent_crops %table.table.table-striped %tr @@ -28,7 +52,7 @@ %th Scientific names %th Added by %th When - - @crops.each do |c| + - @recent_crops.each do |c| %tr %td= link_to c.name, c %td= link_to c.en_wikipedia_url, c.en_wikipedia_url @@ -42,5 +66,5 @@ ago. %div.pagination - = page_entries_info @crops, :model => "crops" - = will_paginate @crops + = page_entries_info @recent_crops, :model => "crops" + = will_paginate @recent_crops From e40fad76fd93249a49a4dfab51a8c1597c5b4cc1 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Sat, 31 Jan 2015 10:39:17 +1100 Subject: [PATCH 17/67] exclude pending approval crops from default crops scope --- app/models/crop.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/crop.rb b/app/models/crop.rb index 5a63b31d2..d58f9a7a0 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -21,7 +21,7 @@ class Crop < ActiveRecord::Base has_and_belongs_to_many :posts before_destroy {|crop| crop.posts.clear} - default_scope { order("lower(name) asc") } + default_scope { where(:approved => true).order("lower(name) asc") } scope :recent, -> { reorder("created_at desc") } scope :toplevel, -> { where(:parent_id => nil) } scope :popular, -> { reorder("plantings_count desc, lower(name) asc") } From a8c203aea0647a7cd24c7ac4198e9ba0ae7419b4 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Sun, 1 Feb 2015 09:32:50 +1100 Subject: [PATCH 18/67] send emails to all crop wranglers when a new crop is requested --- app/controllers/crops_controller.rb | 6 +++++ app/mailers/notifier.rb | 5 ++++ app/models/crop.rb | 10 ++++---- app/views/notifier/new_crop_request.html.haml | 7 ++++++ spec/factories/crop.rb | 5 ++++ spec/mailers/notifier_spec.rb | 25 +++++++++++++++++++ 6 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 app/views/notifier/new_crop_request.html.haml diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index aae0cc928..293e48711 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -113,6 +113,12 @@ class CropsController < ApplicationController respond_to do |format| if @crop.save + if current_member.has_role? :crop_wrangler + Role.crop_wranglers.each do |w| + Notifier.new_crop_request(w, @crop).deliver! + end + end + format.html { redirect_to @crop, notice: 'Crop was successfully created.' } format.json { render json: @crop, status: :created, location: @crop } else diff --git a/app/mailers/notifier.rb b/app/mailers/notifier.rb index 0d6aa6db3..fa1c6e9e9 100644 --- a/app/mailers/notifier.rb +++ b/app/mailers/notifier.rb @@ -22,4 +22,9 @@ class Notifier < ActionMailer::Base end end + def new_crop_request(member, request) + @member, @request = member, request + mail(:to => @member.email, :subject => "New crop request") + end + end diff --git a/app/models/crop.rb b/app/models/crop.rb index d58f9a7a0..87d1639d5 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -21,11 +21,11 @@ class Crop < ActiveRecord::Base has_and_belongs_to_many :posts before_destroy {|crop| crop.posts.clear} - default_scope { where(:approved => true).order("lower(name) asc") } - scope :recent, -> { reorder("created_at desc") } - scope :toplevel, -> { where(:parent_id => nil) } - scope :popular, -> { reorder("plantings_count desc, lower(name) asc") } - scope :randomized, -> { reorder('random()') } # ok on sqlite and psql, but not on mysql + default_scope { order("lower(name) asc") } + scope :recent, -> { where(:approved => true).reorder("created_at desc") } + scope :toplevel, -> { where(approved => true, :parent_id => nil) } + scope :popular, -> { where(:approved => true).reorder("plantings_count desc, lower(name) asc") } + scope :randomized, -> { where(:approved => true).reorder('random()') } # ok on sqlite and psql, but not on mysql scope :pending_approval, -> { where(:approved => false) } validates :en_wikipedia_url, diff --git a/app/views/notifier/new_crop_request.html.haml b/app/views/notifier/new_crop_request.html.haml new file mode 100644 index 000000000..2fc16df7d --- /dev/null +++ b/app/views/notifier/new_crop_request.html.haml @@ -0,0 +1,7 @@ +- site_name = ENV['GROWSTUFF_SITE_NAME'] +%p Hello #{@member.login_name}, + +%p + A new crop has been requested. View, edit, approve or reject the request: + + = link_to "Request for #{@request}", crop_url(@request) diff --git a/spec/factories/crop.rb b/spec/factories/crop.rb index c6839e983..ec519fa1e 100644 --- a/spec/factories/crop.rb +++ b/spec/factories/crop.rb @@ -54,6 +54,11 @@ FactoryGirl.define do name "Swiss chard" end + #for testing crop request + factory :crop_request do + name "Ultra berry" + end + end end diff --git a/spec/mailers/notifier_spec.rb b/spec/mailers/notifier_spec.rb index 4c7ac59a3..d0155e5f0 100644 --- a/spec/mailers/notifier_spec.rb +++ b/spec/mailers/notifier_spec.rb @@ -44,4 +44,29 @@ describe Notifier do end end + + + describe "new crop request" do + let(:member) { FactoryGirl.create(:crop_wrangling_member) } + let(:crop) { FactoryGirl.create(:crop_request) } + let(:mail) { Notifier.new_crop_request(member, crop) } + + it 'sets the subject correctly' do + mail.subject.should == "New crop request" + end + + it 'comes from noreply@growstuff.org' do + mail.from.should == ['noreply@growstuff.org'] + end + + it 'sends the mail to the recipient of the notification' do + mail.to.should == [member.email] + end + + it 'includes the requested crop URL' do + mail.body.encoded.should match crop_url(crop) + end + + end + end From 1741567e19b284cc4860c20fa22337f3208b9358 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Sat, 31 Jan 2015 23:53:47 +0000 Subject: [PATCH 19/67] Add tests for display of date ranges. They fail for me with the error undefined method `days_until_harvest_min=' for # --- spec/factories/seeds.rb | 2 ++ spec/features/seeds/adding_seeds_spec.rb | 2 +- spec/features/seeds/misc_seeds_spec.rb | 25 ++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/spec/factories/seeds.rb b/spec/factories/seeds.rb index 227a83a86..323cdf2f2 100644 --- a/spec/factories/seeds.rb +++ b/spec/factories/seeds.rb @@ -11,6 +11,8 @@ FactoryGirl.define do organic 'unknown' gmo 'unknown' heirloom 'unknown' + days_until_maturity_min nil + days_until_maturity_max nil factory :tradable_seed do tradable_to "locally" diff --git a/spec/features/seeds/adding_seeds_spec.rb b/spec/features/seeds/adding_seeds_spec.rb index e69b380d6..366c3d748 100644 --- a/spec/features/seeds/adding_seeds_spec.rb +++ b/spec/features/seeds/adding_seeds_spec.rb @@ -29,7 +29,7 @@ feature "Harvesting a crop", :js => true do expect(page).to have_content "Successfully added maize seed to your stash" expect(page).to have_content "Quantity: 42" - expect(page).to have_content "Days until maturity: 999" + expect(page).to have_content "Days until maturity: 999–1999" expect(page).to have_content "certified organic" expect(page).to have_content "non-certified GMO-free" expect(page).to have_content "Heirloom? heirloom" diff --git a/spec/features/seeds/misc_seeds_spec.rb b/spec/features/seeds/misc_seeds_spec.rb index 11f1d6c09..961df2888 100644 --- a/spec/features/seeds/misc_seeds_spec.rb +++ b/spec/features/seeds/misc_seeds_spec.rb @@ -45,5 +45,30 @@ feature "seeds" do click_link 'Delete' current_path.should eq seeds_path end + + scenario "view seeds with max and min days until harvest" do + seed = FactoryGirl.create(:seed, :days_until_harvest_min => 5, :days_until_harvest_max => 7) + visit seed_path(seed) + expect(page).to have_content "Days until maturity: 5–7" + end + + scenario "view seeds with only max days until harvest" do + seed = FactoryGirl.create(:seed, :days_until_harvest_max => 7) + visit seed_path(seed) + expect(page).to have_content "Days until maturity: 7" + end + + scenario "view seeds with only min days until harvest" do + seed = FactoryGirl.create(:seed, :days_until_harvest_min => 5) + visit seed_path(seed) + expect(page).to have_content "Days until maturity: 5" + end + + scenario "view seeds with neither max nor min days until harvest" do + seed = FactoryGirl.create(:seed) + visit seed_path(seed) + expect(page).to have_content "Days until maturity: unknown" + end + end end From 6aa37e6e269a49e1b01c3bd2cc5424c6bbde5dae Mon Sep 17 00:00:00 2001 From: Mackenzie Morgan Date: Sun, 1 Feb 2015 00:27:04 -0500 Subject: [PATCH 20/67] adding CMS via comfortable mexican sofa gem --- Gemfile | 2 + Gemfile.lock | 42 ++++++ .../comfy/admin/cms/custom.js.coffee | 1 + .../stylesheets/comfy/admin/cms/custom.sass | 1 + .../initializers/comfortable_mexican_sofa.rb | 121 +++++++++++++++ config/routes.rb | 5 + .../sample-site/categories/files.yml | 1 + .../sample-site/categories/pages.yml | 1 + .../sample-site/categories/snippets.yml | 1 + .../sample-site/files/_sample.jpg.yml | 5 + db/cms_fixtures/sample-site/files/sample.jpg | Bin 0 -> 6400 bytes .../layouts/default/attributes.yml | 1 + .../sample-site/layouts/default/content.html | 5 + .../sample-site/layouts/default/javascript.js | 1 + .../layouts/default/nested/attributes.yml | 2 + .../layouts/default/nested/content.haml | 3 + .../layouts/default/nested/javascript.js | 1 + .../layouts/default/nested/stylesheet.css | 1 + .../layouts/default/stylesheet.css | 1 + .../sample-site/pages/index/attributes.yml | 6 + .../pages/index/child/attributes.yml | 3 + .../sample-site/pages/index/child/left.haml | 1 + .../sample-site/pages/index/child/right.html | 1 + .../pages/index/child/thumbnail.png | Bin 0 -> 6600 bytes .../sample-site/pages/index/content.html | 2 + .../snippets/default/attributes.yml | 4 + .../sample-site/snippets/default/content.html | 1 + db/migrate/20150201052245_create_cms.rb | 140 ++++++++++++++++++ db/schema.rb | 122 ++++++++++++++- 29 files changed, 474 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/comfy/admin/cms/custom.js.coffee create mode 100644 app/assets/stylesheets/comfy/admin/cms/custom.sass create mode 100644 config/initializers/comfortable_mexican_sofa.rb create mode 100644 db/cms_fixtures/sample-site/categories/files.yml create mode 100644 db/cms_fixtures/sample-site/categories/pages.yml create mode 100644 db/cms_fixtures/sample-site/categories/snippets.yml create mode 100644 db/cms_fixtures/sample-site/files/_sample.jpg.yml create mode 100644 db/cms_fixtures/sample-site/files/sample.jpg create mode 100644 db/cms_fixtures/sample-site/layouts/default/attributes.yml create mode 100644 db/cms_fixtures/sample-site/layouts/default/content.html create mode 100644 db/cms_fixtures/sample-site/layouts/default/javascript.js create mode 100644 db/cms_fixtures/sample-site/layouts/default/nested/attributes.yml create mode 100644 db/cms_fixtures/sample-site/layouts/default/nested/content.haml create mode 100644 db/cms_fixtures/sample-site/layouts/default/nested/javascript.js create mode 100644 db/cms_fixtures/sample-site/layouts/default/nested/stylesheet.css create mode 100644 db/cms_fixtures/sample-site/layouts/default/stylesheet.css create mode 100644 db/cms_fixtures/sample-site/pages/index/attributes.yml create mode 100644 db/cms_fixtures/sample-site/pages/index/child/attributes.yml create mode 100644 db/cms_fixtures/sample-site/pages/index/child/left.haml create mode 100644 db/cms_fixtures/sample-site/pages/index/child/right.html create mode 100644 db/cms_fixtures/sample-site/pages/index/child/thumbnail.png create mode 100644 db/cms_fixtures/sample-site/pages/index/content.html create mode 100644 db/cms_fixtures/sample-site/snippets/default/attributes.yml create mode 100644 db/cms_fixtures/sample-site/snippets/default/content.html create mode 100644 db/migrate/20150201052245_create_cms.rb diff --git a/Gemfile b/Gemfile index fcf7b39d4..d6278d87c 100644 --- a/Gemfile +++ b/Gemfile @@ -32,6 +32,8 @@ gem 'cancancan', '~> 1.9' # for checking member privileges gem 'gibbon' # for Mailchimp newsletter subscriptions gem 'csv_shaper' # CSV export +gem 'comfortable_mexican_sofa', '~> 1.12.0' # content management system + # vendored activemerchant for testing- needed for bogus paypal # gateway monkeypatch gem 'activemerchant', '1.33.0', diff --git a/Gemfile.lock b/Gemfile.lock index d54873d81..48afdd1da 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -33,6 +33,8 @@ GEM activesupport (= 4.1.9) builder (~> 3.1) erubis (~> 2.7.0) + active_link_to (1.0.2) + actionpack activemodel (4.1.9) activesupport (= 4.1.9) builder (~> 3.1) @@ -48,6 +50,9 @@ GEM tzinfo (~> 1.1) addressable (2.3.6) arel (5.0.1.20140414130214) + autoprefixer-rails (5.1.1) + execjs + json bcrypt (3.1.9) better_errors (2.0.0) coderay (>= 1.0.0) @@ -58,6 +63,10 @@ GEM bluecloth (2.2.0) bootstrap-datepicker-rails (1.3.0.2) railties (>= 3.0) + bootstrap-sass (3.3.3) + autoprefixer-rails (>= 5.0.0.1) + sass (>= 3.2.19) + bootstrap_form (2.2.0) builder (3.2.2) byebug (3.5.1) columnize (~> 0.8) @@ -73,7 +82,13 @@ GEM capybara-email (2.4.0) capybara (~> 2.4) mail + climate_control (0.0.3) + activesupport (>= 3.0) cliver (0.3.2) + cocaine (0.5.5) + climate_control (>= 0.0.3, < 1.0) + codemirror-rails (4.8) + railties (>= 3.0, < 5) coderay (1.1.0) coffee-rails (4.1.0) coffee-script (>= 2.2.0) @@ -83,6 +98,21 @@ GEM execjs coffee-script-source (1.8.0) columnize (0.9.0) + comfortable_mexican_sofa (1.12.7) + active_link_to (>= 1.0.0) + bootstrap-sass (>= 3.2.0) + bootstrap_form (>= 2.2.0) + codemirror-rails (>= 3.0.0) + coffee-rails (>= 3.1.0) + haml-rails (>= 0.3.0) + jquery-rails (>= 3.0.0) + jquery-ui-rails (>= 5.0.0) + kramdown (>= 1.0.0) + paperclip (>= 4.0.0) + plupload-rails (>= 1.2.1) + rails (>= 4.0.0, < 5) + rails-i18n (>= 4.0.0) + sass-rails (>= 4.0.3) commonjs (0.2.7) coveralls (0.7.1) multi_json (~> 1.3) @@ -171,6 +201,7 @@ GEM sprockets-rails json (1.8.2) kgio (2.9.2) + kramdown (1.5.0) launchy (2.4.3) addressable (~> 2.3) leaflet-markercluster-rails (0.7.0) @@ -212,7 +243,14 @@ GEM multi_json (~> 1.3) omniauth-oauth (~> 1.0) orm_adapter (0.5.0) + paperclip (4.2.1) + activemodel (>= 3.0.0) + activesupport (>= 3.0.0) + cocaine (~> 0.5.3) + mime-types pg (0.17.1) + plupload-rails (1.2.1) + rails (>= 3.1) poltergeist (1.5.1) capybara (~> 2.1) cliver (~> 0.3.1) @@ -237,6 +275,9 @@ GEM bundler (>= 1.3.0, < 2.0) railties (= 4.1.9) sprockets-rails (~> 2.0) + rails-i18n (4.0.3) + i18n (~> 0.6) + railties (~> 4.0) rails_12factor (0.0.3) rails_serve_static_assets rails_stdout_logging @@ -348,6 +389,7 @@ DEPENDENCIES capybara capybara-email coffee-rails (~> 4.1.0) + comfortable_mexican_sofa (~> 1.12.0) coveralls csv_shaper dalli diff --git a/app/assets/javascripts/comfy/admin/cms/custom.js.coffee b/app/assets/javascripts/comfy/admin/cms/custom.js.coffee new file mode 100644 index 000000000..d40d4c9c3 --- /dev/null +++ b/app/assets/javascripts/comfy/admin/cms/custom.js.coffee @@ -0,0 +1 @@ +# Custom JS for the admin area \ No newline at end of file diff --git a/app/assets/stylesheets/comfy/admin/cms/custom.sass b/app/assets/stylesheets/comfy/admin/cms/custom.sass new file mode 100644 index 000000000..328d897f1 --- /dev/null +++ b/app/assets/stylesheets/comfy/admin/cms/custom.sass @@ -0,0 +1 @@ +// custom CSS for admin area \ No newline at end of file diff --git a/config/initializers/comfortable_mexican_sofa.rb b/config/initializers/comfortable_mexican_sofa.rb new file mode 100644 index 000000000..e8f8dfa35 --- /dev/null +++ b/config/initializers/comfortable_mexican_sofa.rb @@ -0,0 +1,121 @@ +# encoding: utf-8 + +ComfortableMexicanSofa.configure do |config| + # Title of the admin area + # config.cms_title = 'ComfortableMexicanSofa CMS Engine' + + # Controller that is inherited from CmsAdmin::BaseController + # config.base_controller = 'ApplicationController' + + # Module responsible for authentication. You can replace it with your own. + # It simply needs to have #authenticate method. See http_auth.rb for reference. + # config.admin_auth = 'ComfyAdminAuthentication' + + # Module responsible for authorization on admin side. It should have #authorize + # method that returns true or false based on params and loaded instance + # variables available for a given controller. + # config.admin_authorization = 'ComfyAdminAuthorization' + + # Module responsible for public authentication. Similar to the above. You also + # will have access to @cms_site, @cms_layout, @cms_page so you can use them in + # your logic. Default module doesn't do anything. + # config.public_auth = 'ComfyPublicAuthentication' + + # When arriving at /cms-admin you may chose to redirect to arbirtary path, + # for example '/cms-admin/users' + # config.admin_route_redirect = '' + + # File uploads use Paperclip and can support filesystem or s3 uploads. Override + # the upload method and appropriate settings based on Paperclip. For S3 see: + # http://rdoc.info/gems/paperclip/2.3.8/Paperclip/Storage/S3, and for + # filesystem see: http://rdoc.info/gems/paperclip/2.3.8/Paperclip/Storage/Filesystem + # If you are using S3 and HTTPS, pass :s3_protocol => '' to have URLs that use the protocol of the page + # config.upload_file_options = {:url => '/system/:class/:id/:attachment/:style/:filename'} + + # Sofa allows you to setup entire site from files. Database is updated with each + # request (if necessary). Please note that database entries are destroyed if there's + # no corresponding file. Fixtures are disabled by default. + # config.enable_fixtures = false + + # Path where fixtures can be located. + # config.fixtures_path = File.expand_path('db/cms_fixtures', Rails.root) + + # Importing fixtures into Database + # To load fixtures into the database just run this rake task: + # local: $ rake comfortable_mexican_sofa:fixtures:import FROM=example.local TO=localhost + # Heroku: $ heroku run rake comfortable_mexican_sofa:fixtures:import FROM=example.local TO=yourapp.herokuapp.com + # From indicates folder the fixtures are in and to is the Site hostname you have defined in the database. + + # Exporting fixtures into Files + # If you need to dump database contents into fixture files run: + # local: $ rake comfortable_mexican_sofa:fixtures:export FROM=localhost TO=example.local + # Heroku: $ heroku run rake comfortable_mexican_sofa:fixtures:export FROM=yourapp.herokuapp.com TO=example.local + # This will create example.local folder and dump all content from example.com Site. + + # Content for Layouts, Pages and Snippets has a revision history. You can revert + # a previous version using this system. You can control how many revisions per + # object you want to keep. Set it to 0 if you wish to turn this feature off. + # config.revisions_limit = 25 + + # Locale definitions. If you want to define your own locale merge + # {:locale => 'Locale Title'} with this. + # config.locales = {:en => 'English', :es => 'Español'} + + # Admin interface will respect the locale of the site being managed. However you can + # force it to English by setting this to `:en` + # config.admin_locale = nil + + # A class that is included as a sweeper to admin base controller if it's set + # config.admin_cache_sweeper = nil + + # By default you cannot have irb code inside your layouts/pages/snippets. + # Generally this is to prevent putting something like this: + # <% User.delete_all %> but if you really want to allow it... + # config.allow_irb = false + + # Whitelist of all helper methods that can be used via {{cms:helper}} tag. By default + # all helpers are allowed except `eval`, `send`, `call` and few others. Empty array + # will prevent rendering of all helpers. + # config.allowed_helpers = nil + + # Whitelist of partials paths that can be used via {{cms:partial}} tag. All partials + # are accessible by default. Empty array will prevent rendering of all partials. + # config.allowed_partials = nil + + # Site aliases, if you want to have aliases for your site. Good for harmonizing + # production env with dev/testing envs. + # e.g. config.hostname_aliases = {'host.com' => 'host.inv', 'host_a.com' => ['host.lvh.me', 'host.dev']} + # Default is nil (not used) + # config.hostname_aliases = nil + + # Reveal partials that can be overwritten in the admin area. + # Default is false. + # config.reveal_cms_partials = false + +end + +# Default credentials for ComfortableMexicanSofa::AccessControl::AdminAuthentication +# YOU REALLY WANT TO CHANGE THIS BEFORE PUTTING YOUR SITE LIVE +ComfortableMexicanSofa::AccessControl::AdminAuthentication.username = 'username' +ComfortableMexicanSofa::AccessControl::AdminAuthentication.password = 'password' + +# Uncomment this module and `config.admin_auth` above to use custom admin authentication +# module ComfyAdminAuthentication +# def authenticate +# return true +# end +# end + +# Uncomment this module and `config.admin_authorization` above to use custom admin authorization +# module ComfyAdminAuthorization +# def authorize +# return true +# end +# end + +# Uncomment this module and `config.public_auth` above to use custom public authentication +# module ComfyPublicAuthentication +# def authenticate +# return true +# end +# end diff --git a/config/routes.rb b/config/routes.rb index ceca68687..a6d29bc9d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,5 +1,10 @@ Growstuff::Application.routes.draw do + comfy_route :cms_admin, :path => '/admin' + + # Make sure this routeset is defined last + comfy_route :cms, :path => '/', :sitemap => false + resources :plant_parts devise_for :members, :controllers => { :registrations => "registrations", :passwords => "passwords" } diff --git a/db/cms_fixtures/sample-site/categories/files.yml b/db/cms_fixtures/sample-site/categories/files.yml new file mode 100644 index 000000000..2e59d3264 --- /dev/null +++ b/db/cms_fixtures/sample-site/categories/files.yml @@ -0,0 +1 @@ +- File Category \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/categories/pages.yml b/db/cms_fixtures/sample-site/categories/pages.yml new file mode 100644 index 000000000..fec395558 --- /dev/null +++ b/db/cms_fixtures/sample-site/categories/pages.yml @@ -0,0 +1 @@ +- Page Category \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/categories/snippets.yml b/db/cms_fixtures/sample-site/categories/snippets.yml new file mode 100644 index 000000000..a7d06fda6 --- /dev/null +++ b/db/cms_fixtures/sample-site/categories/snippets.yml @@ -0,0 +1 @@ +- Snippet Category \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/files/_sample.jpg.yml b/db/cms_fixtures/sample-site/files/_sample.jpg.yml new file mode 100644 index 000000000..b978f0651 --- /dev/null +++ b/db/cms_fixtures/sample-site/files/_sample.jpg.yml @@ -0,0 +1,5 @@ +label: Fixture File +description: Fixture Description +categories: + - category_a + - category_b \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/files/sample.jpg b/db/cms_fixtures/sample-site/files/sample.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2b3a42b36a5c084bf1f701487a26aa533b6041e2 GIT binary patch literal 6400 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 LhZIuX;naTt+W*7| literal 0 HcmV?d00001 diff --git a/db/cms_fixtures/sample-site/layouts/default/attributes.yml b/db/cms_fixtures/sample-site/layouts/default/attributes.yml new file mode 100644 index 000000000..6f1626b7c --- /dev/null +++ b/db/cms_fixtures/sample-site/layouts/default/attributes.yml @@ -0,0 +1 @@ +label: Default Fixture Layout \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/layouts/default/content.html b/db/cms_fixtures/sample-site/layouts/default/content.html new file mode 100644 index 000000000..f2707392b --- /dev/null +++ b/db/cms_fixtures/sample-site/layouts/default/content.html @@ -0,0 +1,5 @@ + + + {{ cms:page:content }} + + \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/layouts/default/javascript.js b/db/cms_fixtures/sample-site/layouts/default/javascript.js new file mode 100644 index 000000000..6959d8bfc --- /dev/null +++ b/db/cms_fixtures/sample-site/layouts/default/javascript.js @@ -0,0 +1 @@ +// default js \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/layouts/default/nested/attributes.yml b/db/cms_fixtures/sample-site/layouts/default/nested/attributes.yml new file mode 100644 index 000000000..754f082c4 --- /dev/null +++ b/db/cms_fixtures/sample-site/layouts/default/nested/attributes.yml @@ -0,0 +1,2 @@ +label: Default Fixture Nested Layout +position: 42 \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/layouts/default/nested/content.haml b/db/cms_fixtures/sample-site/layouts/default/nested/content.haml new file mode 100644 index 000000000..2f09fd402 --- /dev/null +++ b/db/cms_fixtures/sample-site/layouts/default/nested/content.haml @@ -0,0 +1,3 @@ +{{ cms:page_file:thumbnail:url }} +.left {{ cms:page:left }} +.right {{ cms:page:right }} \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/layouts/default/nested/javascript.js b/db/cms_fixtures/sample-site/layouts/default/nested/javascript.js new file mode 100644 index 000000000..2508c22ed --- /dev/null +++ b/db/cms_fixtures/sample-site/layouts/default/nested/javascript.js @@ -0,0 +1 @@ +// nested js \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/layouts/default/nested/stylesheet.css b/db/cms_fixtures/sample-site/layouts/default/nested/stylesheet.css new file mode 100644 index 000000000..034f6fb9c --- /dev/null +++ b/db/cms_fixtures/sample-site/layouts/default/nested/stylesheet.css @@ -0,0 +1 @@ +div{float:left} \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/layouts/default/stylesheet.css b/db/cms_fixtures/sample-site/layouts/default/stylesheet.css new file mode 100644 index 000000000..cd8b4f19d --- /dev/null +++ b/db/cms_fixtures/sample-site/layouts/default/stylesheet.css @@ -0,0 +1 @@ +body{color: red} \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/pages/index/attributes.yml b/db/cms_fixtures/sample-site/pages/index/attributes.yml new file mode 100644 index 000000000..56616f972 --- /dev/null +++ b/db/cms_fixtures/sample-site/pages/index/attributes.yml @@ -0,0 +1,6 @@ +label: Home Fixture Page +layout: default +target_page: '/child' +categories: + - category_a + - category_b \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/pages/index/child/attributes.yml b/db/cms_fixtures/sample-site/pages/index/child/attributes.yml new file mode 100644 index 000000000..d8602e148 --- /dev/null +++ b/db/cms_fixtures/sample-site/pages/index/child/attributes.yml @@ -0,0 +1,3 @@ +label: Child Fixture Page +layout: nested +position: 42 diff --git a/db/cms_fixtures/sample-site/pages/index/child/left.haml b/db/cms_fixtures/sample-site/pages/index/child/left.haml new file mode 100644 index 000000000..756907e5e --- /dev/null +++ b/db/cms_fixtures/sample-site/pages/index/child/left.haml @@ -0,0 +1 @@ += "Child Page Left Fixture Content" \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/pages/index/child/right.html b/db/cms_fixtures/sample-site/pages/index/child/right.html new file mode 100644 index 000000000..3ac08e9ab --- /dev/null +++ b/db/cms_fixtures/sample-site/pages/index/child/right.html @@ -0,0 +1 @@ +Child Page Right Fixture Content \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/pages/index/child/thumbnail.png b/db/cms_fixtures/sample-site/pages/index/child/thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..89cf33f55ee298e089b39c4aab4a0e62fdfc065b GIT binary patch literal 6600 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 O#sSwd)GUM9h5rvhyEdc% literal 0 HcmV?d00001 diff --git a/db/cms_fixtures/sample-site/pages/index/content.html b/db/cms_fixtures/sample-site/pages/index/content.html new file mode 100644 index 000000000..fb97a42a7 --- /dev/null +++ b/db/cms_fixtures/sample-site/pages/index/content.html @@ -0,0 +1,2 @@ +Home Page Fixture Contént +{{ cms:snippet:default }} \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/snippets/default/attributes.yml b/db/cms_fixtures/sample-site/snippets/default/attributes.yml new file mode 100644 index 000000000..2113c3ce6 --- /dev/null +++ b/db/cms_fixtures/sample-site/snippets/default/attributes.yml @@ -0,0 +1,4 @@ +label: Default Fixture Snippet +categories: + - category_a + - category_b \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/snippets/default/content.html b/db/cms_fixtures/sample-site/snippets/default/content.html new file mode 100644 index 000000000..48a4995fa --- /dev/null +++ b/db/cms_fixtures/sample-site/snippets/default/content.html @@ -0,0 +1 @@ +Fixture Content for Default Snippet \ No newline at end of file diff --git a/db/migrate/20150201052245_create_cms.rb b/db/migrate/20150201052245_create_cms.rb new file mode 100644 index 000000000..9e999488f --- /dev/null +++ b/db/migrate/20150201052245_create_cms.rb @@ -0,0 +1,140 @@ +class CreateCms < ActiveRecord::Migration + + def self.up + + text_limit = case ActiveRecord::Base.connection.adapter_name + when 'PostgreSQL' + { } + else + { :limit => 16777215 } + end + + # -- Sites -------------------------------------------------------------- + create_table :comfy_cms_sites do |t| + t.string :label, :null => false + t.string :identifier, :null => false + t.string :hostname, :null => false + t.string :path + t.string :locale, :null => false, :default => 'en' + t.boolean :is_mirrored, :null => false, :default => false + end + add_index :comfy_cms_sites, :hostname + add_index :comfy_cms_sites, :is_mirrored + + # -- Layouts ------------------------------------------------------------ + create_table :comfy_cms_layouts do |t| + t.integer :site_id, :null => false + t.integer :parent_id + t.string :app_layout + t.string :label, :null => false + t.string :identifier, :null => false + t.text :content, text_limit + t.text :css, text_limit + t.text :js, text_limit + t.integer :position, :null => false, :default => 0 + t.boolean :is_shared, :null => false, :default => false + t.timestamps + end + add_index :comfy_cms_layouts, [:parent_id, :position] + add_index :comfy_cms_layouts, [:site_id, :identifier], :unique => true + + # -- Pages -------------------------------------------------------------- + create_table :comfy_cms_pages do |t| + t.integer :site_id, :null => false + t.integer :layout_id + t.integer :parent_id + t.integer :target_page_id + t.string :label, :null => false + t.string :slug + t.string :full_path, :null => false + t.text :content_cache, text_limit + t.integer :position, :null => false, :default => 0 + t.integer :children_count, :null => false, :default => 0 + t.boolean :is_published, :null => false, :default => true + t.boolean :is_shared, :null => false, :default => false + t.timestamps + end + add_index :comfy_cms_pages, [:site_id, :full_path] + add_index :comfy_cms_pages, [:parent_id, :position] + + # -- Page Blocks -------------------------------------------------------- + create_table :comfy_cms_blocks do |t| + t.string :identifier, :null => false + t.text :content, text_limit + t.references :blockable, :polymorphic => true + t.timestamps + end + add_index :comfy_cms_blocks, [:identifier] + add_index :comfy_cms_blocks, [:blockable_id, :blockable_type] + + # -- Snippets ----------------------------------------------------------- + create_table :comfy_cms_snippets do |t| + t.integer :site_id, :null => false + t.string :label, :null => false + t.string :identifier, :null => false + t.text :content, text_limit + t.integer :position, :null => false, :default => 0 + t.boolean :is_shared, :null => false, :default => false + t.timestamps + end + add_index :comfy_cms_snippets, [:site_id, :identifier], :unique => true + add_index :comfy_cms_snippets, [:site_id, :position] + + # -- Files -------------------------------------------------------------- + create_table :comfy_cms_files do |t| + t.integer :site_id, :null => false + t.integer :block_id + t.string :label, :null => false + t.string :file_file_name, :null => false + t.string :file_content_type, :null => false + t.integer :file_file_size, :null => false + t.string :description, :limit => 2048 + t.integer :position, :null => false, :default => 0 + t.timestamps + end + add_index :comfy_cms_files, [:site_id, :label] + add_index :comfy_cms_files, [:site_id, :file_file_name] + add_index :comfy_cms_files, [:site_id, :position] + add_index :comfy_cms_files, [:site_id, :block_id] + + # -- Revisions ----------------------------------------------------------- + create_table :comfy_cms_revisions, :force => true do |t| + t.string :record_type, :null => false + t.integer :record_id, :null => false + t.text :data, text_limit + t.datetime :created_at + end + add_index :comfy_cms_revisions, [:record_type, :record_id, :created_at], + :name => 'index_cms_revisions_on_rtype_and_rid_and_created_at' + + # -- Categories --------------------------------------------------------- + create_table :comfy_cms_categories, :force => true do |t| + t.integer :site_id, :null => false + t.string :label, :null => false + t.string :categorized_type, :null => false + end + add_index :comfy_cms_categories, [:site_id, :categorized_type, :label], :unique => true, + :name => 'index_cms_categories_on_site_id_and_cat_type_and_label' + + create_table :comfy_cms_categorizations, :force => true do |t| + t.integer :category_id, :null => false + t.string :categorized_type, :null => false + t.integer :categorized_id, :null => false + end + add_index :comfy_cms_categorizations, [:category_id, :categorized_type, :categorized_id], :unique => true, + :name => 'index_cms_categorizations_on_cat_id_and_catd_type_and_catd_id' + end + + def self.down + drop_table :comfy_cms_sites + drop_table :comfy_cms_layouts + drop_table :comfy_cms_pages + drop_table :comfy_cms_snippets + drop_table :comfy_cms_blocks + drop_table :comfy_cms_files + drop_table :comfy_cms_revisions + drop_table :comfy_cms_categories + drop_table :comfy_cms_categorizations + end +end + diff --git a/db/schema.rb b/db/schema.rb index 9e593a422..91a3b597a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150127043022) do +ActiveRecord::Schema.define(version: 20150201052245) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -53,6 +53,125 @@ ActiveRecord::Schema.define(version: 20150127043022) do add_index "authentications", ["member_id"], name: "index_authentications_on_member_id", using: :btree + create_table "comfy_cms_blocks", force: true do |t| + t.string "identifier", null: false + t.text "content" + t.integer "blockable_id" + t.string "blockable_type" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "comfy_cms_blocks", ["blockable_id", "blockable_type"], name: "index_comfy_cms_blocks_on_blockable_id_and_blockable_type", using: :btree + add_index "comfy_cms_blocks", ["identifier"], name: "index_comfy_cms_blocks_on_identifier", using: :btree + + create_table "comfy_cms_categories", force: true do |t| + t.integer "site_id", null: false + t.string "label", null: false + t.string "categorized_type", null: false + end + + add_index "comfy_cms_categories", ["site_id", "categorized_type", "label"], name: "index_cms_categories_on_site_id_and_cat_type_and_label", unique: true, using: :btree + + create_table "comfy_cms_categorizations", force: true do |t| + t.integer "category_id", null: false + t.string "categorized_type", null: false + t.integer "categorized_id", null: false + end + + add_index "comfy_cms_categorizations", ["category_id", "categorized_type", "categorized_id"], name: "index_cms_categorizations_on_cat_id_and_catd_type_and_catd_id", unique: true, using: :btree + + create_table "comfy_cms_files", force: true do |t| + t.integer "site_id", null: false + t.integer "block_id" + t.string "label", null: false + t.string "file_file_name", null: false + t.string "file_content_type", null: false + t.integer "file_file_size", null: false + t.string "description", limit: 2048 + t.integer "position", default: 0, null: false + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "comfy_cms_files", ["site_id", "block_id"], name: "index_comfy_cms_files_on_site_id_and_block_id", using: :btree + add_index "comfy_cms_files", ["site_id", "file_file_name"], name: "index_comfy_cms_files_on_site_id_and_file_file_name", using: :btree + add_index "comfy_cms_files", ["site_id", "label"], name: "index_comfy_cms_files_on_site_id_and_label", using: :btree + add_index "comfy_cms_files", ["site_id", "position"], name: "index_comfy_cms_files_on_site_id_and_position", using: :btree + + create_table "comfy_cms_layouts", force: true do |t| + t.integer "site_id", null: false + t.integer "parent_id" + t.string "app_layout" + t.string "label", null: false + t.string "identifier", null: false + t.text "content" + t.text "css" + t.text "js" + t.integer "position", default: 0, null: false + t.boolean "is_shared", default: false, null: false + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "comfy_cms_layouts", ["parent_id", "position"], name: "index_comfy_cms_layouts_on_parent_id_and_position", using: :btree + add_index "comfy_cms_layouts", ["site_id", "identifier"], name: "index_comfy_cms_layouts_on_site_id_and_identifier", unique: true, using: :btree + + create_table "comfy_cms_pages", force: true do |t| + t.integer "site_id", null: false + t.integer "layout_id" + t.integer "parent_id" + t.integer "target_page_id" + t.string "label", null: false + t.string "slug" + t.string "full_path", null: false + t.text "content_cache" + t.integer "position", default: 0, null: false + t.integer "children_count", default: 0, null: false + t.boolean "is_published", default: true, null: false + t.boolean "is_shared", default: false, null: false + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "comfy_cms_pages", ["parent_id", "position"], name: "index_comfy_cms_pages_on_parent_id_and_position", using: :btree + add_index "comfy_cms_pages", ["site_id", "full_path"], name: "index_comfy_cms_pages_on_site_id_and_full_path", using: :btree + + create_table "comfy_cms_revisions", force: true do |t| + t.string "record_type", null: false + t.integer "record_id", null: false + t.text "data" + t.datetime "created_at" + end + + add_index "comfy_cms_revisions", ["record_type", "record_id", "created_at"], name: "index_cms_revisions_on_rtype_and_rid_and_created_at", using: :btree + + create_table "comfy_cms_sites", force: true do |t| + t.string "label", null: false + t.string "identifier", null: false + t.string "hostname", null: false + t.string "path" + t.string "locale", default: "en", null: false + t.boolean "is_mirrored", default: false, null: false + end + + add_index "comfy_cms_sites", ["hostname"], name: "index_comfy_cms_sites_on_hostname", using: :btree + add_index "comfy_cms_sites", ["is_mirrored"], name: "index_comfy_cms_sites_on_is_mirrored", using: :btree + + create_table "comfy_cms_snippets", force: true do |t| + t.integer "site_id", null: false + t.string "label", null: false + t.string "identifier", null: false + t.text "content" + t.integer "position", default: 0, null: false + t.boolean "is_shared", default: false, null: false + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "comfy_cms_snippets", ["site_id", "identifier"], name: "index_comfy_cms_snippets_on_site_id_and_identifier", unique: true, using: :btree + add_index "comfy_cms_snippets", ["site_id", "position"], name: "index_comfy_cms_snippets_on_site_id_and_position", using: :btree + create_table "comments", force: true do |t| t.integer "post_id", null: false t.integer "author_id", null: false @@ -139,6 +258,7 @@ ActiveRecord::Schema.define(version: 20150127043022) do t.decimal "weight_quantity" t.string "weight_unit" t.integer "plant_part_id" + t.float "si_weight" end create_table "harvests_photos", id: false, force: true do |t| From c80b42d9bcb371d93e4bdff0fb54d1c8ed663c9d Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Sun, 1 Feb 2015 16:52:31 +1100 Subject: [PATCH 21/67] change from approved boolean to approval_status string --- app/controllers/crops_controller.rb | 4 ++-- app/models/crop.rb | 10 +++++----- app/views/crops/_form.html.haml | 6 ++++++ ...150130224814_add_requester_and_approved_to_crops.rb | 7 ------- db/migrate/20150130224814_add_requester_to_crops.rb | 6 ++++++ .../20150201053200_add_approval_status_to_crops.rb | 5 +++++ db/schema.rb | 10 +++++----- 7 files changed, 29 insertions(+), 19 deletions(-) delete mode 100644 db/migrate/20150130224814_add_requester_and_approved_to_crops.rb create mode 100644 db/migrate/20150130224814_add_requester_to_crops.rb create mode 100644 db/migrate/20150201053200_add_approval_status_to_crops.rb diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index 293e48711..54ebf468f 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -108,7 +108,7 @@ class CropsController < ApplicationController @crop.creator = current_member else @crop.requester = current_member - @crop.approved = false + @crop.approval_status = "pending" end respond_to do |format| @@ -159,6 +159,6 @@ class CropsController < ApplicationController private def crop_params - params.require(:crop).permit(:en_wikipedia_url, :name, :parent_id, :creator_id, :scientific_names_attributes => [:scientific_name]) + params.require(:crop).permit(:en_wikipedia_url, :name, :parent_id, :creator_id, :approval_status, :scientific_names_attributes => [:scientific_name]) end end diff --git a/app/models/crop.rb b/app/models/crop.rb index 87d1639d5..95999812f 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -22,11 +22,11 @@ class Crop < ActiveRecord::Base before_destroy {|crop| crop.posts.clear} default_scope { order("lower(name) asc") } - scope :recent, -> { where(:approved => true).reorder("created_at desc") } - scope :toplevel, -> { where(approved => true, :parent_id => nil) } - scope :popular, -> { where(:approved => true).reorder("plantings_count desc, lower(name) asc") } - scope :randomized, -> { where(:approved => true).reorder('random()') } # ok on sqlite and psql, but not on mysql - scope :pending_approval, -> { where(:approved => false) } + scope :recent, -> { where(:approval_status => "approved").reorder("created_at desc") } + scope :toplevel, -> { where(approval_status => "approved", :parent_id => nil) } + scope :popular, -> { where(:approval_status => "approved").reorder("plantings_count desc, lower(name) asc") } + scope :randomized, -> { where(:approval_status => "approved").reorder('random()') } # ok on sqlite and psql, but not on mysql + scope :pending_approval, -> { where(:approval_status => "pending") } validates :en_wikipedia_url, :format => { diff --git a/app/views/crops/_form.html.haml b/app/views/crops/_form.html.haml index 0c8fc8c45..17473f13d 100644 --- a/app/views/crops/_form.html.haml +++ b/app/views/crops/_form.html.haml @@ -40,6 +40,12 @@ %label.checkbox = sn.check_box :_destroy = sn.label :_destroy, "Delete" + + .form-group + = f.label :approval_status, 'Approval Status', :class=> 'control-label col-md-2' + .col-md-8 + = f.select(:approval_status, ['rejected', 'pending', 'approved'], {}, {:class => 'form-control'}) + .form-group .form-actions.col-md-offset-2.col-md-8 = f.submit 'Save', :class => 'btn btn-primary' diff --git a/db/migrate/20150130224814_add_requester_and_approved_to_crops.rb b/db/migrate/20150130224814_add_requester_and_approved_to_crops.rb deleted file mode 100644 index e9295f7f9..000000000 --- a/db/migrate/20150130224814_add_requester_and_approved_to_crops.rb +++ /dev/null @@ -1,7 +0,0 @@ -class AddRequesterAndApprovedToCrops < ActiveRecord::Migration - def change - add_column :crops, :requester_id, :integer - add_column :crops, :approved, :boolean, default: true - add_index :crops, :requester_id - end -end diff --git a/db/migrate/20150130224814_add_requester_to_crops.rb b/db/migrate/20150130224814_add_requester_to_crops.rb new file mode 100644 index 000000000..f284a6f68 --- /dev/null +++ b/db/migrate/20150130224814_add_requester_to_crops.rb @@ -0,0 +1,6 @@ +class AddRequesterToCrops < ActiveRecord::Migration + def change + add_column :crops, :requester_id, :integer + add_index :crops, :requester_id + end +end diff --git a/db/migrate/20150201053200_add_approval_status_to_crops.rb b/db/migrate/20150201053200_add_approval_status_to_crops.rb new file mode 100644 index 000000000..07b1e0879 --- /dev/null +++ b/db/migrate/20150201053200_add_approval_status_to_crops.rb @@ -0,0 +1,5 @@ +class AddApprovalStatusToCrops < ActiveRecord::Migration + def change + add_column :crops, :approval_status, :string, default: "approved" + end +end diff --git a/db/schema.rb b/db/schema.rb index 73e87cf3f..951353dc9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150130224814) do +ActiveRecord::Schema.define(version: 20150201053200) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -62,16 +62,16 @@ ActiveRecord::Schema.define(version: 20150130224814) do end create_table "crops", force: true do |t| - t.string "name", null: false + t.string "name", null: false t.string "en_wikipedia_url" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "slug" t.integer "parent_id" t.integer "plantings_count", default: 0 t.integer "creator_id" t.integer "requester_id" - t.boolean "approved", default: true + t.string "approval_status", default: "approved" end add_index "crops", ["name"], name: "index_crops_on_name", using: :btree From 776b5450f9377e60c59d1c2fe6f6cf7781ea0e95 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Sun, 1 Feb 2015 17:20:48 +1100 Subject: [PATCH 22/67] requester receives email when crop request is approved --- app/controllers/crops_controller.rb | 7 +++++ app/mailers/notifier.rb | 5 ++++ .../notifier/crop_request_approved.html.haml | 13 +++++++++ spec/mailers/notifier_spec.rb | 29 +++++++++++++++++++ 4 files changed, 54 insertions(+) create mode 100644 app/views/notifier/crop_request_approved.html.haml diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index 54ebf468f..a4528ca19 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -133,8 +133,15 @@ class CropsController < ApplicationController def update @crop = Crop.find(params[:id]) + previous_status = @crop.approval_status + respond_to do |format| if @crop.update(crop_params) + if previous_status == "pending" + requester = @crop.requester + new_status = @crop.approval_status + Notifier.crop_request_approved(requester, @crop).deliver! if new_status == "approved" + end format.html { redirect_to @crop, notice: 'Crop was successfully updated.' } format.json { head :no_content } else diff --git a/app/mailers/notifier.rb b/app/mailers/notifier.rb index fa1c6e9e9..81c7352ed 100644 --- a/app/mailers/notifier.rb +++ b/app/mailers/notifier.rb @@ -27,4 +27,9 @@ class Notifier < ActionMailer::Base mail(:to => @member.email, :subject => "New crop request") end + def crop_request_approved(member, crop) + @member, @crop = member, crop + mail(:to => @member.email, :subject => "#{crop.name.capitalize} has been approved") + end + end diff --git a/app/views/notifier/crop_request_approved.html.haml b/app/views/notifier/crop_request_approved.html.haml new file mode 100644 index 000000000..5fe184f1a --- /dev/null +++ b/app/views/notifier/crop_request_approved.html.haml @@ -0,0 +1,13 @@ +- site_name = ENV['GROWSTUFF_SITE_NAME'] +%p Hello #{@member.login_name}, + +%p + Your request for the new crop: #{link_to @crop.name, crop_url(@crop)} has been approved! + +%ul + %li + = link_to "Plant #{@crop.name}", new_planting_url(crop_id: @crop.id) + %li + = link_to "Harvest #{@crop.name}", new_harvest_url(crop_id: @crop.id) + %li + = link_to "Stash seeds for #{@crop.name}", new_seed_url(crop_id: @crop.id) diff --git a/spec/mailers/notifier_spec.rb b/spec/mailers/notifier_spec.rb index d0155e5f0..0a813bdc5 100644 --- a/spec/mailers/notifier_spec.rb +++ b/spec/mailers/notifier_spec.rb @@ -66,7 +66,36 @@ describe Notifier do it 'includes the requested crop URL' do mail.body.encoded.should match crop_url(crop) end + end + + describe "crop approved" do + let(:member) { FactoryGirl.create(:member) } + let(:crop) { FactoryGirl.create(:crop) } + let(:mail) { Notifier.crop_request_approved(member, crop) } + + it 'sets the subject correctly' do + expect(mail.subject).to eq "Magic bean has been approved" + end + + it 'comes from noreply@growstuff.org' do + expect(mail.from).to eq ['noreply@growstuff.org'] + end + + it 'sends the mail to the recipient of the notification' do + expect(mail.to).to eq [member.email] + end + + it 'includes the approved crop URL' do + expect(mail.body.encoded).to match crop_url(crop) + end + + it 'includes links to plant, harvest and stash seeds for the new crop' do + expect(mail.body.encoded).to match new_planting_url(crop_id: crop.id) + expect(mail.body.encoded).to match new_harvest_url(crop_id: crop.id) + expect(mail.body.encoded).to match new_seed_url(crop_id: crop.id) + end end + end From e86200b94219322e9d3c6e5fc136bb42e2f133d7 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Sun, 1 Feb 2015 17:32:49 +1100 Subject: [PATCH 23/67] requester receives a message when crop request is rejected --- app/controllers/crops_controller.rb | 3 ++- app/mailers/notifier.rb | 5 ++++ app/views/crops/_form.html.haml | 5 ++++ .../notifier/crop_request_rejected.html.haml | 7 +++++ ...62506_add_reason_for_rejection_to_crops.rb | 5 ++++ db/schema.rb | 13 +++++----- spec/factories/crop.rb | 5 ++++ spec/mailers/notifier_spec.rb | 26 +++++++++++++++++++ 8 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 app/views/notifier/crop_request_rejected.html.haml create mode 100644 db/migrate/20150201062506_add_reason_for_rejection_to_crops.rb diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index a4528ca19..5f859b4de 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -141,6 +141,7 @@ class CropsController < ApplicationController requester = @crop.requester new_status = @crop.approval_status Notifier.crop_request_approved(requester, @crop).deliver! if new_status == "approved" + Notifier.crop_request_rejected(requester, @crop).deliver! if new_status == "rejected" end format.html { redirect_to @crop, notice: 'Crop was successfully updated.' } format.json { head :no_content } @@ -166,6 +167,6 @@ class CropsController < ApplicationController private def crop_params - params.require(:crop).permit(:en_wikipedia_url, :name, :parent_id, :creator_id, :approval_status, :scientific_names_attributes => [:scientific_name]) + params.require(:crop).permit(:en_wikipedia_url, :name, :parent_id, :creator_id, :approval_status, :reason_for_rejection, :scientific_names_attributes => [:scientific_name]) end end diff --git a/app/mailers/notifier.rb b/app/mailers/notifier.rb index 81c7352ed..88c5f50f5 100644 --- a/app/mailers/notifier.rb +++ b/app/mailers/notifier.rb @@ -32,4 +32,9 @@ class Notifier < ActionMailer::Base mail(:to => @member.email, :subject => "#{crop.name.capitalize} has been approved") end + def crop_request_rejected(member, crop) + @member, @crop = member, crop + mail(:to => @member.email, :subject => "#{crop.name.capitalize} has been rejected") + end + end diff --git a/app/views/crops/_form.html.haml b/app/views/crops/_form.html.haml index 17473f13d..284faa0eb 100644 --- a/app/views/crops/_form.html.haml +++ b/app/views/crops/_form.html.haml @@ -46,6 +46,11 @@ .col-md-8 = f.select(:approval_status, ['rejected', 'pending', 'approved'], {}, {:class => 'form-control'}) + .form-group + = f.label :reason_for_rejection, 'Reason for rejection', :class => 'control-label col-md-2' + .col-md-8= f.text_area :reason_for_rejection, :rows => 6, :class => 'form-control' + + .form-group .form-actions.col-md-offset-2.col-md-8 = f.submit 'Save', :class => 'btn btn-primary' diff --git a/app/views/notifier/crop_request_rejected.html.haml b/app/views/notifier/crop_request_rejected.html.haml new file mode 100644 index 000000000..315f7036d --- /dev/null +++ b/app/views/notifier/crop_request_rejected.html.haml @@ -0,0 +1,7 @@ +- site_name = ENV['GROWSTUFF_SITE_NAME'] +%p Hello #{@member.login_name}, + +%p + Your request for the new crop: #{link_to @crop.name, crop_url(@crop)} has been rejected for the following reason. + + = @crop.reason_for_rejection \ No newline at end of file diff --git a/db/migrate/20150201062506_add_reason_for_rejection_to_crops.rb b/db/migrate/20150201062506_add_reason_for_rejection_to_crops.rb new file mode 100644 index 000000000..0fd283a67 --- /dev/null +++ b/db/migrate/20150201062506_add_reason_for_rejection_to_crops.rb @@ -0,0 +1,5 @@ +class AddReasonForRejectionToCrops < ActiveRecord::Migration + def change + add_column :crops, :reason_for_rejection, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 951353dc9..554190279 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150201053200) do +ActiveRecord::Schema.define(version: 20150201062506) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -62,16 +62,17 @@ ActiveRecord::Schema.define(version: 20150201053200) do end create_table "crops", force: true do |t| - t.string "name", null: false + t.string "name", null: false t.string "en_wikipedia_url" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "slug" t.integer "parent_id" - t.integer "plantings_count", default: 0 + t.integer "plantings_count", default: 0 t.integer "creator_id" t.integer "requester_id" - t.string "approval_status", default: "approved" + t.string "approval_status", default: "approved" + t.text "reason_for_rejection" end add_index "crops", ["name"], name: "index_crops_on_name", using: :btree diff --git a/spec/factories/crop.rb b/spec/factories/crop.rb index ec519fa1e..ed4aefe54 100644 --- a/spec/factories/crop.rb +++ b/spec/factories/crop.rb @@ -59,6 +59,11 @@ FactoryGirl.define do name "Ultra berry" end + factory :rejected_crop do + name "Fail bean" + reason_for_rejection "Totally fake" + end + end end diff --git a/spec/mailers/notifier_spec.rb b/spec/mailers/notifier_spec.rb index 0a813bdc5..dc7a4a63e 100644 --- a/spec/mailers/notifier_spec.rb +++ b/spec/mailers/notifier_spec.rb @@ -97,5 +97,31 @@ describe Notifier do end + describe "crop rejected" do + let(:member) { FactoryGirl.create(:member) } + let(:crop) { FactoryGirl.create(:rejected_crop) } + let(:mail) { Notifier.crop_request_rejected(member, crop) } + + it 'sets the subject correctly' do + expect(mail.subject).to eq "Fail bean has been rejected" + end + + it 'comes from noreply@growstuff.org' do + expect(mail.from).to eq ['noreply@growstuff.org'] + end + + it 'sends the mail to the recipient of the notification' do + expect(mail.to).to eq [member.email] + end + + it 'includes the rejected crop URL' do + expect(mail.body.encoded).to match crop_url(crop) + end + + it 'includes the reason for rejection' do + expect(mail.body.encoded).to match "Totally fake" + end + end + end From d02edc3dd1236f0559e35a883bcb85336d1bf8ed Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Sun, 1 Feb 2015 17:42:21 +1100 Subject: [PATCH 24/67] don't show sci name fields to regular users in crop form --- app/views/crops/_form.html.haml | 43 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/app/views/crops/_form.html.haml b/app/views/crops/_form.html.haml index 284faa0eb..1573b9b4d 100644 --- a/app/views/crops/_form.html.haml +++ b/app/views/crops/_form.html.haml @@ -27,28 +27,31 @@ .col-md-8 = collection_select(:crop, :parent_id, Crop.all, :id, :name, {:include_blank => true}, :class => 'form-control') %span.help-block Optional. For setting up crop hierarchies for varieties etc. - %p - %span.help-block - You may enter up to 3 scientific names for a crop. Most crops will have only one. - = f.fields_for :scientific_names do |sn| - .form-group - = sn.label :scientific_name, "Scientific name", :class => 'control-label col-md-2' - .col-md-8 - = sn.text_field :scientific_name, :class => 'form-control' - .col-md-2 - - if sn.object && sn.object.persisted? - %label.checkbox - = sn.check_box :_destroy - = sn.label :_destroy, "Delete" - .form-group - = f.label :approval_status, 'Approval Status', :class=> 'control-label col-md-2' - .col-md-8 - = f.select(:approval_status, ['rejected', 'pending', 'approved'], {}, {:class => 'form-control'}) + - if can? :wrangle, @crop + %p + %span.help-block + You may enter up to 3 scientific names for a crop. Most crops will have only one. + = f.fields_for :scientific_names do |sn| + .form-group + = sn.label :scientific_name, "Scientific name", :class => 'control-label col-md-2' + .col-md-8 + = sn.text_field :scientific_name, :class => 'form-control' + .col-md-2 + - if sn.object && sn.object.persisted? + %label.checkbox + = sn.check_box :_destroy + = sn.label :_destroy, "Delete" - .form-group - = f.label :reason_for_rejection, 'Reason for rejection', :class => 'control-label col-md-2' - .col-md-8= f.text_area :reason_for_rejection, :rows => 6, :class => 'form-control' + - unless @crop.new_record? + .form-group + = f.label :approval_status, 'Approval Status', :class=> 'control-label col-md-2' + .col-md-8 + = f.select(:approval_status, ['rejected', 'pending', 'approved'], {}, {:class => 'form-control'}) + + .form-group + = f.label :reason_for_rejection, 'Reason for rejection', :class => 'control-label col-md-2' + .col-md-8= f.text_area :reason_for_rejection, :rows => 6, :class => 'form-control' .form-group From 4211ebec7686b90900742f91011b04d870dd7f7e Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Sun, 1 Feb 2015 17:56:51 +1100 Subject: [PATCH 25/67] add request notes to crop request --- app/controllers/crops_controller.rb | 2 +- app/models/crop.rb | 4 +++ app/views/crops/_form.html.haml | 34 +++++++++++++------ app/views/crops/show.html.haml | 9 +++++ ...150201064502_add_request_notes_to_crops.rb | 5 +++ db/schema.rb | 3 +- 6 files changed, 45 insertions(+), 12 deletions(-) create mode 100644 db/migrate/20150201064502_add_request_notes_to_crops.rb diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index 5f859b4de..32cb7649a 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -167,6 +167,6 @@ class CropsController < ApplicationController private def crop_params - params.require(:crop).permit(:en_wikipedia_url, :name, :parent_id, :creator_id, :approval_status, :reason_for_rejection, :scientific_names_attributes => [:scientific_name]) + params.require(:crop).permit(:en_wikipedia_url, :name, :parent_id, :creator_id, :approval_status, :request_notes, :reason_for_rejection, :scientific_names_attributes => [:scientific_name]) end end diff --git a/app/models/crop.rb b/app/models/crop.rb index 95999812f..abae4f4d5 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -105,6 +105,10 @@ class Crop < ActiveRecord::Base return true end + def pending? + approval_status == "pending" + end + # Crop.interesting # returns a list of interesting crops, for use on the homepage etc def Crop.interesting diff --git a/app/views/crops/_form.html.haml b/app/views/crops/_form.html.haml index 1573b9b4d..e0d4c3f72 100644 --- a/app/views/crops/_form.html.haml +++ b/app/views/crops/_form.html.haml @@ -6,11 +6,13 @@ - @crop.errors.full_messages.each do |msg| %li= msg - %p - %span.help-block - For detailed crop wrangling guidelines, please consult the - =link_to "crop wrangling guide", "http://wiki.growstuff.org/index.php/Crop_wrangling" - on the Growstuff wiki. + - if can? :wrangle, @crop + %p + %span.help-block + For detailed crop wrangling guidelines, please consult the + + =link_to "crop wrangling guide", "http://wiki.growstuff.org/index.php/Crop_wrangling" + on the Growstuff wiki. .form-group = f.label :name, :class => 'control-label col-md-2' @@ -22,13 +24,15 @@ .col-md-8 = f.text_field :en_wikipedia_url, :class => 'form-control' %span.help-block Link to this crop's page on the English language Wikipedia. - .form-group - = f.label :parent_id, 'Parent crop', :class => 'control-label col-md-2' - .col-md-8 - = collection_select(:crop, :parent_id, Crop.all, :id, :name, {:include_blank => true}, :class => 'form-control') - %span.help-block Optional. For setting up crop hierarchies for varieties etc. - if can? :wrangle, @crop + + .form-group + = f.label :parent_id, 'Parent crop', :class => 'control-label col-md-2' + .col-md-8 + = collection_select(:crop, :parent_id, Crop.all, :id, :name, {:include_blank => true}, :class => 'form-control') + %span.help-block Optional. For setting up crop hierarchies for varieties etc. + %p %span.help-block You may enter up to 3 scientific names for a crop. Most crops will have only one. @@ -53,6 +57,16 @@ = f.label :reason_for_rejection, 'Reason for rejection', :class => 'control-label col-md-2' .col-md-8= f.text_area :reason_for_rejection, :rows => 6, :class => 'form-control' + - else + %p + %span.help-block + Provide any additional information that might help us assess your request. + + .form-group + = f.label :request_notes, 'Comments', :class => 'control-label col-md-2' + .col-md-8= f.text_area :request_notes, :rows => 6, :class => 'form-control' + + .form-group .form-actions.col-md-offset-2.col-md-8 diff --git a/app/views/crops/show.html.haml b/app/views/crops/show.html.haml index 8ef425ecd..db62660c3 100644 --- a/app/views/crops/show.html.haml +++ b/app/views/crops/show.html.haml @@ -1,5 +1,14 @@ - content_for :title, @crop.name - content_for :subtitle, @crop.default_scientific_name + +- if can?(:wrangle, @crop) && @crop.pending? + .alert.alert-warning + %b This crop is currently pending approval. + - if @crop.request_notes + %p + Request notes: #{@crop.request_notes} + + - content_for :buttonbar do - if can? :create, Planting = link_to "Plant this", new_planting_path(:crop_id => @crop.id), :class => 'btn btn-default' diff --git a/db/migrate/20150201064502_add_request_notes_to_crops.rb b/db/migrate/20150201064502_add_request_notes_to_crops.rb new file mode 100644 index 000000000..0720bf4cb --- /dev/null +++ b/db/migrate/20150201064502_add_request_notes_to_crops.rb @@ -0,0 +1,5 @@ +class AddRequestNotesToCrops < ActiveRecord::Migration + def change + add_column :crops, :request_notes, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 554190279..ea9fe790e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150201062506) do +ActiveRecord::Schema.define(version: 20150201064502) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -73,6 +73,7 @@ ActiveRecord::Schema.define(version: 20150201062506) do t.integer "requester_id" t.string "approval_status", default: "approved" t.text "reason_for_rejection" + t.text "request_notes" end add_index "crops", ["name"], name: "index_crops_on_name", using: :btree From 5035b65883effdad8f1920f2c1257a6ce6364a19 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Sun, 1 Feb 2015 10:11:55 +0000 Subject: [PATCH 26/67] Fix stupid call-nonexistent-method bug in tests. --- spec/features/seeds/misc_seeds_spec.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/features/seeds/misc_seeds_spec.rb b/spec/features/seeds/misc_seeds_spec.rb index 961df2888..1e434a754 100644 --- a/spec/features/seeds/misc_seeds_spec.rb +++ b/spec/features/seeds/misc_seeds_spec.rb @@ -46,25 +46,25 @@ feature "seeds" do current_path.should eq seeds_path end - scenario "view seeds with max and min days until harvest" do - seed = FactoryGirl.create(:seed, :days_until_harvest_min => 5, :days_until_harvest_max => 7) + scenario "view seeds with max and min days until maturity" do + seed = FactoryGirl.create(:seed, :days_until_maturity_min => 5, :days_until_maturity_max => 7) visit seed_path(seed) expect(page).to have_content "Days until maturity: 5–7" end - scenario "view seeds with only max days until harvest" do - seed = FactoryGirl.create(:seed, :days_until_harvest_max => 7) + scenario "view seeds with only max days until maturity" do + seed = FactoryGirl.create(:seed, :days_until_maturity_max => 7) visit seed_path(seed) expect(page).to have_content "Days until maturity: 7" end - scenario "view seeds with only min days until harvest" do - seed = FactoryGirl.create(:seed, :days_until_harvest_min => 5) + scenario "view seeds with only min days until maturity" do + seed = FactoryGirl.create(:seed, :days_until_maturity_min => 5) visit seed_path(seed) expect(page).to have_content "Days until maturity: 5" end - scenario "view seeds with neither max nor min days until harvest" do + scenario "view seeds with neither max nor min days until maturity" do seed = FactoryGirl.create(:seed) visit seed_path(seed) expect(page).to have_content "Days until maturity: unknown" From 79c60dc7c7ce93943e467e0060a15d4d52c700e5 Mon Sep 17 00:00:00 2001 From: Yoong Kang Lim Date: Sun, 1 Feb 2015 22:26:44 +1100 Subject: [PATCH 27/67] Allow the planting reminder spec to test links in emails properly --- spec/features/planting_reminder_spec.rb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/spec/features/planting_reminder_spec.rb b/spec/features/planting_reminder_spec.rb index 3b8c88bf8..cdcca0e9b 100644 --- a/spec/features/planting_reminder_spec.rb +++ b/spec/features/planting_reminder_spec.rb @@ -5,6 +5,12 @@ feature "Planting reminder email", :js => true do let(:member) { FactoryGirl.create(:member) } let(:mail) { Notifier.planting_reminder(member) } + # Unfortunately, we can't use the default url options for ActionMailer as configured in + # test.rb, since this isn't a mailer spec. + def self.default_url_options + { host: 'localhost', port: 8080 } + end + scenario "has a greeting" do expect(mail).to have_content "Hello" end @@ -36,8 +42,8 @@ feature "Planting reminder email", :js => true do expect(mail).to have_content "most recent plantings you've told us about" expect(mail).to have_content @p1.to_s expect(mail).to have_content @p2.to_s - # can't test for links to your plantings due to this weirdness: - # https://github.com/Skud/growstuff/commit/8e6a57c4429eac88ab934f422ab11bf16b0a7663 + expect(mail).to have_link @p1.to_s, :href => planting_url(@p1) + expect(mail).to have_link @p2.to_s, :href => planting_url(@p2) expect(mail).to have_content "keep your garden records up to date" end end @@ -67,8 +73,8 @@ feature "Planting reminder email", :js => true do expect(mail).to have_content "the last few things you harvested were" expect(mail).to have_content @h1.to_s expect(mail).to have_content @h2.to_s - # can't test for links to your harvests due to this weirdness: - # https://github.com/Skud/growstuff/commit/8e6a57c4429eac88ab934f422ab11bf16b0a7663 + expect(mail).to have_link @h1.to_s, harvest_url(@h1) + expect(mail).to have_link @h2.to_s, harvest_url(@h2) expect(mail).to have_content "Harvested anything else lately?" end From 3791f4aa6f255337333cde8c5be61376d0cee8e4 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Sun, 1 Feb 2015 22:43:22 +1100 Subject: [PATCH 28/67] validate wikipedia url only if crop is approved --- app/models/crop.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/models/crop.rb b/app/models/crop.rb index abae4f4d5..325a9b13d 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -32,7 +32,8 @@ class Crop < ActiveRecord::Base :format => { :with => /\Ahttps?:\/\/en\.wikipedia\.org\/wiki/, :message => 'is not a valid English Wikipedia URL' - } + }, + :if => :approved? def to_s return name @@ -109,6 +110,10 @@ class Crop < ActiveRecord::Base approval_status == "pending" end + def approved? + approval_status == "approved" + end + # Crop.interesting # returns a list of interesting crops, for use on the homepage etc def Crop.interesting From 40d13fadb3b21f7a518bb62317ca8bf916891415 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Sun, 1 Feb 2015 23:29:31 +1100 Subject: [PATCH 29/67] write feature spec for requesting a crop --- app/controllers/crops_controller.rb | 4 +- app/views/crops/wrangle.html.haml | 2 +- spec/factories/crop.rb | 4 ++ spec/features/crops/request_new_crop_spec.rb | 57 ++++++++++++++++++++ 4 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 spec/features/crops/request_new_crop_spec.rb diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index 32cb7649a..8f9816454 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -106,9 +106,11 @@ class CropsController < ApplicationController if current_member.has_role? :crop_wrangler @crop.creator = current_member + success_msg = "Crop was successfully created." else @crop.requester = current_member @crop.approval_status = "pending" + success_msg = "Crop was successfully requested." end respond_to do |format| @@ -119,7 +121,7 @@ class CropsController < ApplicationController end end - format.html { redirect_to @crop, notice: 'Crop was successfully created.' } + format.html { redirect_to @crop, notice: success_msg } format.json { render json: @crop, status: :created, location: @crop } else format.html { render action: "new" } diff --git a/app/views/crops/wrangle.html.haml b/app/views/crops/wrangle.html.haml index 07091c595..5f65e0196 100644 --- a/app/views/crops/wrangle.html.haml +++ b/app/views/crops/wrangle.html.haml @@ -17,7 +17,7 @@ %h2 Requested crops -%table.table.table-striped +%table#requested-crops.table.table-striped %thead %tr %th System name diff --git a/spec/factories/crop.rb b/spec/factories/crop.rb index ed4aefe54..b0513814f 100644 --- a/spec/factories/crop.rb +++ b/spec/factories/crop.rb @@ -57,6 +57,10 @@ FactoryGirl.define do #for testing crop request factory :crop_request do name "Ultra berry" + en_wikipedia_url "" + approval_status "pending" + association :requester, factory: :member + request_notes "Please approve this even though it's fake." end factory :rejected_crop do diff --git a/spec/features/crops/request_new_crop_spec.rb b/spec/features/crops/request_new_crop_spec.rb new file mode 100644 index 000000000..096f2ec8b --- /dev/null +++ b/spec/features/crops/request_new_crop_spec.rb @@ -0,0 +1,57 @@ +require 'rails_helper' + +feature "Requesting a new crop" do + + context "As a regular member" do + + let(:member) { FactoryGirl.create(:member) } + + before { login_as member } + + scenario "Submit request" do + visit new_crop_path + fill_in "Name", with: "Couch potato" + fill_in "Comments", with: "Couch are real for real." + click_button "Save" + expect(page).to have_content "Crop was successfully requested." + end + + end + + context "As a crop wrangler" do + + let(:wrangler) { FactoryGirl.create(:crop_wrangling_member) } + let!(:crop) { FactoryGirl.create(:crop_request) } + + before { login_as wrangler } + + scenario "View pending crops" do + visit wrangle_crops_path + within "#requested-crops" do + expect(page).to have_content "Ultra berry" + end + click_link "Ultra berry" + expect(page).to have_content "This crop is currently pending approval." + expect(page).to have_content "Please approve this even though it's fake." + end + + scenario "Approve a request" do + visit edit_crop_path(crop) + select "approved", from: "Approval Status" + click_button "Save" + expect(page).to have_content "En wikipedia url is not a valid English Wikipedia URL" + fill_in "Wikipedia URL", with: "http://en.wikipedia.org/wiki/Aung_San_Suu_Kyi" + click_button "Save" + expect(page).to have_content "Crop was successfully updated." + end + + scenario "Rejecting a crop" do + visit edit_crop_path(crop) + select "rejected", from: "Approval Status" + click_button "Save" + expect(page).to have_content "Crop was successfully updated." + end + + end + +end \ No newline at end of file From 2f67ffd2f881fb3ccd0482a8746b649ded8778ed Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Mon, 2 Feb 2015 00:01:49 +1100 Subject: [PATCH 30/67] fix regressions --- app/models/crop.rb | 2 +- app/views/crops/wrangle.html.haml | 45 ++++++++++++---------- spec/controllers/crops_controller_spec.rb | 3 +- spec/factories/crop.rb | 1 + spec/features/crops/crop_wranglers_spec.rb | 2 +- spec/mailers/notifier_spec.rb | 6 +-- spec/models/ability_spec.rb | 5 ++- spec/views/crops/wrangle.html.haml_spec.rb | 2 +- 8 files changed, 37 insertions(+), 29 deletions(-) diff --git a/app/models/crop.rb b/app/models/crop.rb index 325a9b13d..f12e7355d 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -23,7 +23,7 @@ class Crop < ActiveRecord::Base default_scope { order("lower(name) asc") } scope :recent, -> { where(:approval_status => "approved").reorder("created_at desc") } - scope :toplevel, -> { where(approval_status => "approved", :parent_id => nil) } + scope :toplevel, -> { where(:approval_status => "approved", :parent_id => nil) } scope :popular, -> { where(:approval_status => "approved").reorder("plantings_count desc, lower(name) asc") } scope :randomized, -> { where(:approval_status => "approved").reorder('random()') } # ok on sqlite and psql, but not on mysql scope :pending_approval, -> { where(:approval_status => "pending") } diff --git a/app/views/crops/wrangle.html.haml b/app/views/crops/wrangle.html.haml index 5f65e0196..e47f854eb 100644 --- a/app/views/crops/wrangle.html.haml +++ b/app/views/crops/wrangle.html.haml @@ -17,27 +17,30 @@ %h2 Requested crops -%table#requested-crops.table.table-striped - %thead - %tr - %th System name - %th English Wikipedia URL - %th Scientific names - %th Requested by - %th When requested - %tbody - - @pending_approval.each do |c| +- if @pending_approval + %table#requested-crops.table.table-striped + %thead %tr - %td= link_to c.name, c - %td= link_to c.en_wikipedia_url, c.en_wikipedia_url - %td - - c.scientific_names.each do |s| - = link_to s.scientific_name, s - %br/ - %td= link_to c.requester, c.requester - %td - = distance_of_time_in_words(c.created_at, Time.zone.now) - ago. + %th System name + %th English Wikipedia URL + %th Scientific names + %th Requested by + %th When requested + %tbody + - @pending_approval.each do |c| + %tr + %td= link_to c.name, c + %td= link_to c.en_wikipedia_url, c.en_wikipedia_url + %td + - c.scientific_names.each do |s| + = link_to s.scientific_name, s + %br/ + %td= link_to c.requester, c.requester + %td + = distance_of_time_in_words(c.created_at, Time.zone.now) + ago. +- else + %p There are no crops pending approval. %h2 Recently added crops @@ -45,7 +48,7 @@ = page_entries_info @recent_crops, :model => "crops" = will_paginate @recent_crops -%table.table.table-striped +%table#recently-added.table.table-striped %tr %th System name %th English Wikipedia URL diff --git a/spec/controllers/crops_controller_spec.rb b/spec/controllers/crops_controller_spec.rb index 5cfe9f4d1..54226c27c 100644 --- a/spec/controllers/crops_controller_spec.rb +++ b/spec/controllers/crops_controller_spec.rb @@ -7,7 +7,8 @@ describe CropsController do def valid_attributes { :name => "Tomato", - :en_wikipedia_url => 'http://en.wikipedia.org/wiki/Tomato' + :en_wikipedia_url => 'http://en.wikipedia.org/wiki/Tomato', + :approval_status => 'approved' } end diff --git a/spec/factories/crop.rb b/spec/factories/crop.rb index b0513814f..261979b45 100644 --- a/spec/factories/crop.rb +++ b/spec/factories/crop.rb @@ -3,6 +3,7 @@ FactoryGirl.define do factory :crop do name "magic bean" en_wikipedia_url "http://en.wikipedia.org/wiki/Magic_bean" + approval_status "approved" creator factory :tomato do diff --git a/spec/features/crops/crop_wranglers_spec.rb b/spec/features/crops/crop_wranglers_spec.rb index 0e0b08fbe..b01e3acc9 100644 --- a/spec/features/crops/crop_wranglers_spec.rb +++ b/spec/features/crops/crop_wranglers_spec.rb @@ -25,7 +25,7 @@ feature "crop wranglers" do scenario "can see list of crops with extra detail of who created a crop" do visit root_path click_link 'Crop Wrangling' - within '.table' do + within '#recently-added' do expect(page).to have_content "#{crops.first.creator.login_name}" end end diff --git a/spec/mailers/notifier_spec.rb b/spec/mailers/notifier_spec.rb index dc7a4a63e..667ded7a2 100644 --- a/spec/mailers/notifier_spec.rb +++ b/spec/mailers/notifier_spec.rb @@ -90,9 +90,9 @@ describe Notifier do end it 'includes links to plant, harvest and stash seeds for the new crop' do - expect(mail.body.encoded).to match new_planting_url(crop_id: crop.id) - expect(mail.body.encoded).to match new_harvest_url(crop_id: crop.id) - expect(mail.body.encoded).to match new_seed_url(crop_id: crop.id) + expect(mail.body.encoded).to match new_planting_url + expect(mail.body.encoded).to match new_harvest_url + expect(mail.body.encoded).to match new_seed_url end end diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 4eccf8916..87d8a3b1d 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -45,11 +45,14 @@ describe Ability do context "standard member" do it "can't manage crops" do - @ability.should_not be_able_to(:create, Crop) @ability.should_not be_able_to(:update, @crop) @ability.should_not be_able_to(:destroy, @crop) end + it "can request crops" do + @ability.should be_able_to(:create, Crop) + end + it "can read crops" do @ability.should be_able_to(:read, @crop) end diff --git a/spec/views/crops/wrangle.html.haml_spec.rb b/spec/views/crops/wrangle.html.haml_spec.rb index 4426382d2..24438899b 100644 --- a/spec/views/crops/wrangle.html.haml_spec.rb +++ b/spec/views/crops/wrangle.html.haml_spec.rb @@ -12,7 +12,7 @@ describe "crops/wrangle" do crops = WillPaginate::Collection.create(page, per_page, total_entries) do |pager| pager.replace([ @tomato, @maize ]) end - assign(:crops, crops) + assign(:recent_crops, crops) assign(:crop_wranglers, Role.crop_wranglers) end From eca27d18ea37833ed964f97561ef2bd29a85a1a6 Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Sun, 1 Feb 2015 18:14:25 +0000 Subject: [PATCH 31/67] Reword "days until maturity" on seed form. --- app/views/seeds/_form.html.haml | 16 ++++++++++------ spec/features/seeds/adding_seeds_spec.rb | 4 ++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/views/seeds/_form.html.haml b/app/views/seeds/_form.html.haml index 9472e2799..bb4528ee5 100644 --- a/app/views/seeds/_form.html.haml +++ b/app/views/seeds/_form.html.haml @@ -22,12 +22,16 @@ .col-md-2 = f.text_field :plant_before, :class => 'add-datepicker form-control', :value => @seed.plant_before ? @seed.plant_before.to_s(:ymd) : '' .form-group - = f.label :days_until_maturity_min, 'Days until maturity, min:', :class => 'control-label col-md-2' - .col-md-2 - = f.number_field :days_until_maturity_min, :class => 'form-control' - = f.label :days_until_maturity_max, 'Days until maturity, max:', :class => 'control-label col-md-2' - .col-md-2 - = f.number_field :days_until_maturity_max, :class => 'form-control' + = f.label :days_until_maturity_min, 'Days until maturity:', :class => 'control-label col-md-2' + .input-group + .col-md-2 + = f.number_field :days_until_maturity_min, :class => 'form-control' + .col-md-1 + = f.label :days_until_maturity_max, 'to', :class => 'control-label' + .col-md-2 + = f.number_field :days_until_maturity_max, :class => 'form-control' + .col-md-1 + = f.label :dummy, 'days', :class => 'control-label' .form-group = f.label :organic, 'Organic?', :class => 'control-label col-md-2' .col-md-8 diff --git a/spec/features/seeds/adding_seeds_spec.rb b/spec/features/seeds/adding_seeds_spec.rb index 0abbd164c..79eff1732 100644 --- a/spec/features/seeds/adding_seeds_spec.rb +++ b/spec/features/seeds/adding_seeds_spec.rb @@ -17,8 +17,8 @@ feature "Seeds", :js => true do within "form#new_seed" do fill_in "Quantity:", :with => 42 fill_in "Plant before:", :with => "2014-06-15" - fill_in "Days until maturity, min:", :with => 999 - fill_in "Days until maturity, max:", :with => 1999 + fill_in "Days until maturity:", :with => 999 + fill_in "to", :with => 1999 select "certified organic", :from => "Organic?" select "non-certified GMO-free", :from => "GMO?" select "heirloom", :from => "Heirloom?" From 7326acba81242dc34a5814548b167a78995cd684 Mon Sep 17 00:00:00 2001 From: Mackenzie Morgan Date: Sun, 1 Feb 2015 21:56:06 -0500 Subject: [PATCH 32/67] add cms routes --- config/routes.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index a6d29bc9d..8f4fa215b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,9 +1,5 @@ Growstuff::Application.routes.draw do - comfy_route :cms_admin, :path => '/admin' - - # Make sure this routeset is defined last - comfy_route :cms, :path => '/', :sitemap => false resources :plant_parts @@ -89,6 +85,8 @@ Growstuff::Application.routes.draw do get '/admin/newsletter' => 'admin#newsletter', :as => :admin_newsletter get '/admin/:action' => 'admin#:action' - +# CMS stuff -- must remain LAST + comfy_route :cms_admin, :path => '/cms' + comfy_route :cms, :path => '/', :sitemap => false end From af39df5e0c45bc3343a3754943aeb402cc5953a1 Mon Sep 17 00:00:00 2001 From: Skud Date: Mon, 2 Feb 2015 18:04:56 +1100 Subject: [PATCH 33/67] Fixed test failure if elasticsearch isn't present in test env --- app/models/crop.rb | 13 +++++-- db/schema.rb | 97 +++++++++++++++++++++++----------------------- 2 files changed, 58 insertions(+), 52 deletions(-) diff --git a/app/models/crop.rb b/app/models/crop.rb index 82d1e24a0..00f08f528 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -31,7 +31,7 @@ class Crop < ActiveRecord::Base :with => /\Ahttps?:\/\/en\.wikipedia\.org\/wiki/, :message => 'is not a valid English Wikipedia URL' } - + #################################### # Elastic search configuration include Elasticsearch::Model @@ -81,13 +81,18 @@ class Crop < ActiveRecord::Base include: { scientific_names: { only: :scientific_name }, alternate_names: { only: :name } - }) + }) end + # update the Elasticsearch index (only if we're using it in this + # environment) def update_index(name_obj) - __elasticsearch__.index_document + if ENV["GROWSTUFF_ELASTICSEARCH"] == "true" + __elasticsearch__.index_document + end end - #################################### + + # End Elasticsearch section def to_s return name diff --git a/db/schema.rb b/db/schema.rb index bf80810c7..e54fc8911 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -20,16 +20,16 @@ ActiveRecord::Schema.define(version: 20150129034206) do t.string "name", null: false t.boolean "is_paid" t.boolean "is_permanent_paid" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" end create_table "accounts", force: true do |t| t.integer "member_id", null: false t.integer "account_type_id" t.datetime "paid_until" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" end create_table "alternate_names", force: true do |t| @@ -46,8 +46,8 @@ ActiveRecord::Schema.define(version: 20150129034206) do t.string "uid" t.string "token" t.string "secret" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.string "name" end @@ -57,15 +57,15 @@ ActiveRecord::Schema.define(version: 20150129034206) do t.integer "post_id", null: false t.integer "author_id", null: false t.text "body", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" end create_table "crops", force: true do |t| t.string "name", null: false t.string "en_wikipedia_url" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.string "slug" t.integer "parent_id" t.integer "plantings_count", default: 0 @@ -94,8 +94,8 @@ ActiveRecord::Schema.define(version: 20150129034206) do t.string "name", null: false t.text "description", null: false t.integer "owner_id", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.string "slug" end @@ -105,8 +105,8 @@ ActiveRecord::Schema.define(version: 20150129034206) do t.string "name", null: false t.integer "owner_id" t.string "slug", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.text "description" t.boolean "active", default: true t.string "location" @@ -116,7 +116,7 @@ ActiveRecord::Schema.define(version: 20150129034206) do t.string "area_unit" end - add_index "gardens", ["owner_id"], name: "index_gardens_on_user_id", using: :btree + add_index "gardens", ["owner_id"], name: "index_gardens_on_owner_id", using: :btree add_index "gardens", ["slug"], name: "index_gardens_on_slug", unique: true, using: :btree create_table "gardens_photos", id: false, force: true do |t| @@ -133,8 +133,8 @@ ActiveRecord::Schema.define(version: 20150129034206) do t.decimal "quantity" t.string "unit" t.text "description" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.string "slug" t.decimal "weight_quantity" t.string "weight_unit" @@ -167,8 +167,8 @@ ActiveRecord::Schema.define(version: 20150129034206) do t.integer "failed_attempts", default: 0 t.string "unlock_token" t.datetime "locked_at" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.string "login_name" t.string "slug" t.boolean "tos_agreement" @@ -183,11 +183,11 @@ ActiveRecord::Schema.define(version: 20150129034206) do t.boolean "send_planting_reminder", default: true end - add_index "members", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree - add_index "members", ["email"], name: "index_users_on_email", unique: true, using: :btree - add_index "members", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree - add_index "members", ["slug"], name: "index_users_on_slug", unique: true, using: :btree - add_index "members", ["unlock_token"], name: "index_users_on_unlock_token", unique: true, using: :btree + add_index "members", ["confirmation_token"], name: "index_members_on_confirmation_token", unique: true, using: :btree + add_index "members", ["email"], name: "index_members_on_email", unique: true, using: :btree + add_index "members", ["reset_password_token"], name: "index_members_on_reset_password_token", unique: true, using: :btree + add_index "members", ["slug"], name: "index_members_on_slug", unique: true, using: :btree + add_index "members", ["unlock_token"], name: "index_members_on_unlock_token", unique: true, using: :btree create_table "members_roles", id: false, force: true do |t| t.integer "member_id" @@ -201,8 +201,8 @@ ActiveRecord::Schema.define(version: 20150129034206) do t.text "body" t.boolean "read", default: false t.integer "post_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" end create_table "order_items", force: true do |t| @@ -210,13 +210,13 @@ ActiveRecord::Schema.define(version: 20150129034206) do t.integer "product_id" t.integer "price" t.integer "quantity" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" end create_table "orders", force: true do |t| - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.datetime "completed_at" t.integer "member_id" t.string "paypal_express_token" @@ -233,8 +233,8 @@ ActiveRecord::Schema.define(version: 20150129034206) do t.integer "owner_id", null: false t.string "thumbnail_url", null: false t.string "fullsize_url", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.string "title", null: false t.string "license_name", null: false t.string "license_url" @@ -249,8 +249,8 @@ ActiveRecord::Schema.define(version: 20150129034206) do create_table "plant_parts", force: true do |t| t.string "name" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.string "slug" end @@ -260,8 +260,8 @@ ActiveRecord::Schema.define(version: 20150129034206) do t.date "planted_at" t.integer "quantity" t.text "description" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.string "slug" t.string "sunniness" t.string "planted_from" @@ -276,21 +276,22 @@ ActiveRecord::Schema.define(version: 20150129034206) do t.integer "author_id", null: false t.string "subject", null: false t.text "body", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.string "slug" t.integer "forum_id" + t.integer "parent_id" end - add_index "posts", ["created_at", "author_id"], name: "index_updates_on_created_at_and_user_id", using: :btree - add_index "posts", ["slug"], name: "index_updates_on_slug", unique: true, using: :btree + add_index "posts", ["created_at", "author_id"], name: "index_posts_on_created_at_and_author_id", using: :btree + add_index "posts", ["slug"], name: "index_posts_on_slug", unique: true, using: :btree create_table "products", force: true do |t| t.string "name", null: false t.text "description", null: false t.integer "min_price", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.integer "account_type_id" t.integer "paid_months" t.integer "recommended_price" @@ -299,8 +300,8 @@ ActiveRecord::Schema.define(version: 20150129034206) do create_table "roles", force: true do |t| t.string "name", null: false t.text "description" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.string "slug" end @@ -309,8 +310,8 @@ ActiveRecord::Schema.define(version: 20150129034206) do create_table "scientific_names", force: true do |t| t.string "scientific_name", null: false t.integer "crop_id", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.integer "creator_id" end @@ -320,8 +321,8 @@ ActiveRecord::Schema.define(version: 20150129034206) do t.text "description" t.integer "quantity" t.date "plant_before" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.string "tradable_to", default: "nowhere" t.string "slug" end From a795d452c61f9a729da4cf0a482f0dfab85ceb0e Mon Sep 17 00:00:00 2001 From: Yoong Kang Lim Date: Mon, 2 Feb 2015 21:15:46 +1100 Subject: [PATCH 34/67] Remove redundant have_content expectations --- spec/features/planting_reminder_spec.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/spec/features/planting_reminder_spec.rb b/spec/features/planting_reminder_spec.rb index cdcca0e9b..3d694c013 100644 --- a/spec/features/planting_reminder_spec.rb +++ b/spec/features/planting_reminder_spec.rb @@ -40,10 +40,8 @@ feature "Planting reminder email", :js => true do scenario "lists plantings" do expect(mail).to have_content "most recent plantings you've told us about" - expect(mail).to have_content @p1.to_s - expect(mail).to have_content @p2.to_s - expect(mail).to have_link @p1.to_s, :href => planting_url(@p1) - expect(mail).to have_link @p2.to_s, :href => planting_url(@p2) + expect(mail).to have_link @p1.to_s, planting_url(@p1) + expect(mail).to have_link @p2.to_s, planting_url(@p2) expect(mail).to have_content "keep your garden records up to date" end end @@ -71,8 +69,6 @@ feature "Planting reminder email", :js => true do scenario "lists harvests" do expect(mail).to have_content "the last few things you harvested were" - expect(mail).to have_content @h1.to_s - expect(mail).to have_content @h2.to_s expect(mail).to have_link @h1.to_s, harvest_url(@h1) expect(mail).to have_link @h2.to_s, harvest_url(@h2) expect(mail).to have_content "Harvested anything else lately?" From 47dc94f820917a73fe4e9bdcd8f0c6a15cd8d81d Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Tue, 3 Feb 2015 13:18:59 +1100 Subject: [PATCH 35/67] reason_for_rejection is required if marked as rejected --- app/models/crop.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/models/crop.rb b/app/models/crop.rb index f12e7355d..06359be0a 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -35,6 +35,8 @@ class Crop < ActiveRecord::Base }, :if => :approved? + validates :reason_for_rejection, :presence => true, :if => :rejected? + def to_s return name end @@ -114,6 +116,10 @@ class Crop < ActiveRecord::Base approval_status == "approved" end + def rejected? + approval_status == "rejected" + end + # Crop.interesting # returns a list of interesting crops, for use on the homepage etc def Crop.interesting From 3e65656c7b8594d7aa4feedcc6d19e8791d2376a Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Tue, 3 Feb 2015 13:25:14 +1100 Subject: [PATCH 36/67] add meta data to crop pending alert --- app/views/crops/show.html.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/crops/show.html.haml b/app/views/crops/show.html.haml index db62660c3..fc32e6594 100644 --- a/app/views/crops/show.html.haml +++ b/app/views/crops/show.html.haml @@ -4,7 +4,8 @@ - if can?(:wrangle, @crop) && @crop.pending? .alert.alert-warning %b This crop is currently pending approval. - - if @crop.request_notes + %p This crop was requested by #{@crop.requester} on #{@crop.created_at}. + - unless @crop.request_notes.blank? %p Request notes: #{@crop.request_notes} From d6cb20e2c4b43d3b14ddaeb62528a80db5cd83b3 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Tue, 3 Feb 2015 13:27:41 +1100 Subject: [PATCH 37/67] make reasons for rejection a select input --- app/models/crop.rb | 4 ++++ app/views/crops/_form.html.haml | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/models/crop.rb b/app/models/crop.rb index 06359be0a..364c2e6b4 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -120,6 +120,10 @@ class Crop < ActiveRecord::Base approval_status == "rejected" end + def reasons_for_rejection + [ "already in database", "not edible", "not enough information", "other" ] + end + # Crop.interesting # returns a list of interesting crops, for use on the homepage etc def Crop.interesting diff --git a/app/views/crops/_form.html.haml b/app/views/crops/_form.html.haml index e0d4c3f72..e9cd81ac1 100644 --- a/app/views/crops/_form.html.haml +++ b/app/views/crops/_form.html.haml @@ -55,7 +55,8 @@ .form-group = f.label :reason_for_rejection, 'Reason for rejection', :class => 'control-label col-md-2' - .col-md-8= f.text_area :reason_for_rejection, :rows => 6, :class => 'form-control' + .col-md-8 + = f.select(:reason_for_rejection, @crop.reasons_for_rejection, {:include_blank => true}, {:class => 'form-control'}) - else %p From 0993917dc6a284933a478e9a2849a834d26ced3c Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Tue, 3 Feb 2015 13:28:44 +1100 Subject: [PATCH 38/67] define approval status options in model --- app/models/crop.rb | 4 ++++ app/views/crops/_form.html.haml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/crop.rb b/app/models/crop.rb index 364c2e6b4..ba123d46d 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -120,6 +120,10 @@ class Crop < ActiveRecord::Base approval_status == "rejected" end + def approval_statuses + [ 'rejected', 'pending', 'approved' ] + end + def reasons_for_rejection [ "already in database", "not edible", "not enough information", "other" ] end diff --git a/app/views/crops/_form.html.haml b/app/views/crops/_form.html.haml index e9cd81ac1..a58fab91c 100644 --- a/app/views/crops/_form.html.haml +++ b/app/views/crops/_form.html.haml @@ -51,7 +51,7 @@ .form-group = f.label :approval_status, 'Approval Status', :class=> 'control-label col-md-2' .col-md-8 - = f.select(:approval_status, ['rejected', 'pending', 'approved'], {}, {:class => 'form-control'}) + = f.select(:approval_status, @crop.approval_statuses, {}, {:class => 'form-control'}) .form-group = f.label :reason_for_rejection, 'Reason for rejection', :class => 'control-label col-md-2' From 7db4dee61a3903f7870b9b6bc8bd51672830b58e Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Tue, 3 Feb 2015 13:30:21 +1100 Subject: [PATCH 39/67] add alert on crop show when rejected --- app/views/crops/show.html.haml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/views/crops/show.html.haml b/app/views/crops/show.html.haml index fc32e6594..deadb5f05 100644 --- a/app/views/crops/show.html.haml +++ b/app/views/crops/show.html.haml @@ -8,7 +8,10 @@ - unless @crop.request_notes.blank? %p Request notes: #{@crop.request_notes} - + +- if @crop.rejected? + .alert.alert-warning + %b This crop was rejected for the following reason: #{@crop.reason_for_rejection}. - content_for :buttonbar do - if can? :create, Planting From b95975d63250ca49cb87108515426666b78ebc14 Mon Sep 17 00:00:00 2001 From: Mackenzie Morgan Date: Mon, 2 Feb 2015 23:47:53 -0500 Subject: [PATCH 40/67] swap footer over to CMS snippets and set CMS to use Devise for auth --- app/views/layouts/_footer.html.haml | 26 ++------------ .../initializers/comfortable_mexican_sofa.rb | 34 +++++-------------- spec/features/footer_spec.rb | 12 ++----- 3 files changed, 13 insertions(+), 59 deletions(-) diff --git a/app/views/layouts/_footer.html.haml b/app/views/layouts/_footer.html.haml index 3feaaa57b..e7dba1d25 100644 --- a/app/views/layouts/_footer.html.haml +++ b/app/views/layouts/_footer.html.haml @@ -2,28 +2,8 @@ .container .row .col-md-4#about-growstuff - %ul - %li= link_to t('about'), "http://wiki.growstuff.org/index.php/About%20Growstuff" - %li= link_to t('our_values'), "http://wiki.growstuff.org/index.php/Values" - %li= link_to t('open_source'), "https://github.com/Growstuff/growstuff" - %li= link_to t('growstuff_team'), "http://wiki.growstuff.org/index.php/Team" - %li= link_to t('get_involved'), "http://wiki.growstuff.org/index.php/Get_involved" + != cms_snippet_content(:footer1) .col-md-4#policies - %ul - %li= link_to t('terms_of_service'), url_for(:controller => '/policy', :action => 'tos') - %li= link_to t('privacy_policy'), url_for(:controller => '/policy', :action => 'privacy') - %li= link_to t('data_use_policy'), url_for(:controller => '/policy', :action => 'api') - %li= link_to t('community_guidelines'), url_for(:controller => '/policy', :action => 'community') + != cms_snippet_content(:footer2) .col-md-4#contact - %ul - %li= link_to t('support_'), url_for(:controller => '/support') - %li= link_to t('contact'), url_for(:controller => '/about', :action => 'contact') - %p - = link_to('http://twitter.com/growstufforg', :target => "_blank") do - = image_tag("twitter_32.png", :alt => 'Twitter: @growstufforg') -   - = link_to('https://www.facebook.com/Growstufforg', :target => "_blank") do - = image_tag("facebook_32.png", :alt => 'Facebook') -   - = link_to('http://blog.growstuff.org/', :target => "_blank") do - = image_tag("blog_32.png", :alt => 'Growstuff Blog') + != cms_snippet_content(:footer3) diff --git a/config/initializers/comfortable_mexican_sofa.rb b/config/initializers/comfortable_mexican_sofa.rb index e8f8dfa35..b70bc3afc 100644 --- a/config/initializers/comfortable_mexican_sofa.rb +++ b/config/initializers/comfortable_mexican_sofa.rb @@ -9,7 +9,7 @@ ComfortableMexicanSofa.configure do |config| # Module responsible for authentication. You can replace it with your own. # It simply needs to have #authenticate method. See http_auth.rb for reference. - # config.admin_auth = 'ComfyAdminAuthentication' + config.admin_auth = 'CmsDeviseAuth' # Module responsible for authorization on admin side. It should have #authorize # method that returns true or false based on params and loaded instance @@ -94,28 +94,10 @@ ComfortableMexicanSofa.configure do |config| end -# Default credentials for ComfortableMexicanSofa::AccessControl::AdminAuthentication -# YOU REALLY WANT TO CHANGE THIS BEFORE PUTTING YOUR SITE LIVE -ComfortableMexicanSofa::AccessControl::AdminAuthentication.username = 'username' -ComfortableMexicanSofa::AccessControl::AdminAuthentication.password = 'password' - -# Uncomment this module and `config.admin_auth` above to use custom admin authentication -# module ComfyAdminAuthentication -# def authenticate -# return true -# end -# end - -# Uncomment this module and `config.admin_authorization` above to use custom admin authorization -# module ComfyAdminAuthorization -# def authorize -# return true -# end -# end - -# Uncomment this module and `config.public_auth` above to use custom public authentication -# module ComfyPublicAuthentication -# def authenticate -# return true -# end -# end +module CmsDeviseAuth + def authenticate + unless current_user && current_user.has_role?(:admin) + redirect_to root_path, :alert => 'Permission denied. Please sign in as an admin user to use the CMS admin area.' + end + end +end diff --git a/spec/features/footer_spec.rb b/spec/features/footer_spec.rb index 749d948ba..400b153a4 100644 --- a/spec/features/footer_spec.rb +++ b/spec/features/footer_spec.rb @@ -2,19 +2,11 @@ require 'rails_helper' feature "footer" do - scenario "has three columns" do + scenario "footer is on home page" do visit root_path - expect(page).to have_css 'footer #about-growstuff' - expect(page).to have_css 'footer #policies' - expect(page).to have_css 'footer #contact' + expect(page).to have_css 'footer' end # NB: not testing specific content in the footer since I'm going to put them # in the CMS and they'll be variable. - - scenario "contact page has Twitter link" do - visit root_path - click_link 'Contact' - page.should have_link '@growstufforg', :href => 'http://twitter.com/growstufforg' - end end From 87bfceb0353c7bd2acfc5e736fe2baac67825cfe Mon Sep 17 00:00:00 2001 From: Mackenzie Morgan Date: Mon, 2 Feb 2015 23:49:07 -0500 Subject: [PATCH 41/67] make the one-off save the si weight --- lib/tasks/growstuff.rake | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/tasks/growstuff.rake b/lib/tasks/growstuff.rake index 35365ae1e..bfb7b8642 100644 --- a/lib/tasks/growstuff.rake +++ b/lib/tasks/growstuff.rake @@ -319,6 +319,7 @@ namespace :growstuff do task :populate_si_weight => :environment do Harvest.find_each do |h| h.set_si_weight + h.save end end From ff1b94169056c6e4079e62d4db1cc4e91920b3a7 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Wed, 4 Feb 2015 06:56:51 +1100 Subject: [PATCH 42/67] validate that a crop hasn't already been rejected or approved --- app/controllers/crops_controller.rb | 2 +- app/models/crop.rb | 11 +++++++++++ app/views/crops/_form.html.haml | 2 +- spec/features/crops/request_new_crop_spec.rb | 1 + 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index 8f9816454..c4b3cf484 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -169,6 +169,6 @@ class CropsController < ApplicationController private def crop_params - params.require(:crop).permit(:en_wikipedia_url, :name, :parent_id, :creator_id, :approval_status, :request_notes, :reason_for_rejection, :scientific_names_attributes => [:scientific_name]) + params.require(:crop).permit(:en_wikipedia_url, :name, :parent_id, :creator_id, :approval_status, :request_notes, :reason_for_rejection, :scientific_names_attributes => [:scientific_name, :_destroy, :id]) end end diff --git a/app/models/crop.rb b/app/models/crop.rb index ba123d46d..a6e480466 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -37,6 +37,8 @@ class Crop < ActiveRecord::Base validates :reason_for_rejection, :presence => true, :if => :rejected? + validate :approval_status_cannot_be_changed_again + def to_s return name end @@ -232,4 +234,13 @@ class Crop < ActiveRecord::Base where("name ILIKE ?", "%#{query}%") end + # Custom validations + + # This validation addresses a race condition + def approval_status_cannot_be_changed_again + if rejected? || approved? + errors.add(:approval_status, "has already been set to #{approval_status}") + end + end + end diff --git a/app/views/crops/_form.html.haml b/app/views/crops/_form.html.haml index a58fab91c..b5a3b4b5b 100644 --- a/app/views/crops/_form.html.haml +++ b/app/views/crops/_form.html.haml @@ -47,7 +47,7 @@ = sn.check_box :_destroy = sn.label :_destroy, "Delete" - - unless @crop.new_record? + - unless @crop.new_record? || !@crop.pending? .form-group = f.label :approval_status, 'Approval Status', :class=> 'control-label col-md-2' .col-md-8 diff --git a/spec/features/crops/request_new_crop_spec.rb b/spec/features/crops/request_new_crop_spec.rb index 096f2ec8b..49c52fc95 100644 --- a/spec/features/crops/request_new_crop_spec.rb +++ b/spec/features/crops/request_new_crop_spec.rb @@ -22,6 +22,7 @@ feature "Requesting a new crop" do let(:wrangler) { FactoryGirl.create(:crop_wrangling_member) } let!(:crop) { FactoryGirl.create(:crop_request) } + let!(:already_approved) { FactoryGirl.create(:crop) } before { login_as wrangler } From abece6473b9f6a1ddfaf6b172727a9419f4be716 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Wed, 4 Feb 2015 14:18:10 +1100 Subject: [PATCH 43/67] make rejected and pending crops viewable on wrangle crops page --- app/controllers/crops_controller.rb | 14 +++++- app/models/ability.rb | 3 ++ app/models/crop.rb | 4 +- app/views/crops/_form.html.haml | 2 +- app/views/crops/wrangle.html.haml | 67 +++++++++++++++-------------- 5 files changed, 53 insertions(+), 37 deletions(-) diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index c4b3cf484..37316ad6a 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -32,8 +32,18 @@ class CropsController < ApplicationController # GET /crops/wrangle def wrangle - @recent_crops = Crop.recent.paginate(:page => params[:page]) - @pending_approval = Crop.pending_approval + @approval_status = params[:approval_status] + case @approval_status + when "pending" + @crops = Crop.pending_approval + when "rejected" + @crops = Crop.rejected + else + @crops = Crop.recent + end + + @crops = @crops.paginate(:page => params[:page]) + @crop_wranglers = Role.crop_wranglers respond_to do |format| format.html diff --git a/app/models/ability.rb b/app/models/ability.rb index 51c03e048..8cf9a2efb 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -21,6 +21,9 @@ class Ability cannot :read, Account cannot :read, AccountType + # and nobody should be able to view these expect admins and crop wranglers + cannot :read, Crop, :approval_status => "rejected" + if member # managing your own user settings diff --git a/app/models/crop.rb b/app/models/crop.rb index a6e480466..e99dbf04d 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -27,6 +27,7 @@ class Crop < ActiveRecord::Base scope :popular, -> { where(:approval_status => "approved").reorder("plantings_count desc, lower(name) asc") } scope :randomized, -> { where(:approval_status => "approved").reorder('random()') } # ok on sqlite and psql, but not on mysql scope :pending_approval, -> { where(:approval_status => "pending") } + scope :rejected, -> { where(:approval_status => "rejected") } validates :en_wikipedia_url, :format => { @@ -238,7 +239,8 @@ class Crop < ActiveRecord::Base # This validation addresses a race condition def approval_status_cannot_be_changed_again - if rejected? || approved? + previous = previous_changes.include?(:approval_status) ? previous_changes.approval_status : {} + if previous.include?(:rejected) || previous.include?(:approved) errors.add(:approval_status, "has already been set to #{approval_status}") end end diff --git a/app/views/crops/_form.html.haml b/app/views/crops/_form.html.haml index b5a3b4b5b..a58fab91c 100644 --- a/app/views/crops/_form.html.haml +++ b/app/views/crops/_form.html.haml @@ -47,7 +47,7 @@ = sn.check_box :_destroy = sn.label :_destroy, "Delete" - - unless @crop.new_record? || !@crop.pending? + - unless @crop.new_record? .form-group = f.label :approval_status, 'Approval Status', :class=> 'control-label col-md-2' .col-md-8 diff --git a/app/views/crops/wrangle.html.haml b/app/views/crops/wrangle.html.haml index e47f854eb..933350ae6 100644 --- a/app/views/crops/wrangle.html.haml +++ b/app/views/crops/wrangle.html.haml @@ -15,47 +15,42 @@ %li.crop_wrangler = link_to crop_wrangler.login_name, crop_wrangler -%h2 Requested crops +.tabbable + %ul.nav.nav-tabs + %li{:class => @approval_status.blank? ? 'active' : ''} + = link_to "Recendly added", wrangle_crops_path + %li{:class => @approval_status == "pending" ? 'active' : ''} + = link_to "Pending approval", wrangle_crops_path(:approval_status => "pending") + %li{:class => @approval_status == "rejected" ? 'active' : ''} + = link_to "Rejected", wrangle_crops_path(:approval_status => "rejected") -- if @pending_approval - %table#requested-crops.table.table-striped - %thead - %tr - %th System name - %th English Wikipedia URL - %th Scientific names - %th Requested by - %th When requested - %tbody - - @pending_approval.each do |c| - %tr - %td= link_to c.name, c - %td= link_to c.en_wikipedia_url, c.en_wikipedia_url - %td - - c.scientific_names.each do |s| - = link_to s.scientific_name, s - %br/ - %td= link_to c.requester, c.requester - %td - = distance_of_time_in_words(c.created_at, Time.zone.now) - ago. -- else - %p There are no crops pending approval. +%h2 + - if @approval_status == "pending" + Requested Crops + - elsif @approval_status == "rejected" + Rejected Crops + - else + Recently added crops -%h2 Recently added crops %div.pagination - = page_entries_info @recent_crops, :model => "crops" - = will_paginate @recent_crops + = page_entries_info @crops, :model => "crops" + = will_paginate @crops %table#recently-added.table.table-striped %tr %th System name %th English Wikipedia URL %th Scientific names - %th Added by + %th + - if @approval_status == "pending" + Requested by + - elsif @approval_status == "rejected" + Rejected by + - else + Added by %th When - - @recent_crops.each do |c| + - @crops.each do |c| %tr %td= link_to c.name, c %td= link_to c.en_wikipedia_url, c.en_wikipedia_url @@ -63,11 +58,17 @@ - c.scientific_names.each do |s| = link_to s.scientific_name, s %br/ - %td= link_to c.creator, c.creator + %td + - if @approval_status == "pending" + = link_to c.requester, c.requester + - else + = link_to c.creator, c.creator %td = distance_of_time_in_words(c.created_at, Time.zone.now) ago. %div.pagination - = page_entries_info @recent_crops, :model => "crops" - = will_paginate @recent_crops + = page_entries_info @crops, :model => "crops" + = will_paginate @crops + + From 0dd8cbccf0ac52dfa03d75d2268c8166e5dd6cef Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Wed, 4 Feb 2015 14:21:35 +1100 Subject: [PATCH 44/67] refactor default scope on crop --- app/models/crop.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/models/crop.rb b/app/models/crop.rb index e99dbf04d..a1ef6262c 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -21,11 +21,11 @@ class Crop < ActiveRecord::Base has_and_belongs_to_many :posts before_destroy {|crop| crop.posts.clear} - default_scope { order("lower(name) asc") } - scope :recent, -> { where(:approval_status => "approved").reorder("created_at desc") } - scope :toplevel, -> { where(:approval_status => "approved", :parent_id => nil) } - scope :popular, -> { where(:approval_status => "approved").reorder("plantings_count desc, lower(name) asc") } - scope :randomized, -> { where(:approval_status => "approved").reorder('random()') } # ok on sqlite and psql, but not on mysql + default_scope { where(:approval_status => "approved").order("lower(name) asc") } + scope :recent, -> { reorder("created_at desc") } + scope :toplevel, -> { where(:parent_id => nil) } + scope :popular, -> { reorder("plantings_count desc, lower(name) asc") } + scope :randomized, -> { reorder('random()') } # ok on sqlite and psql, but not on mysql scope :pending_approval, -> { where(:approval_status => "pending") } scope :rejected, -> { where(:approval_status => "rejected") } From 80a28085f12a8586ea7cebff2d612297fb34f6ee Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Wed, 4 Feb 2015 14:44:12 +1100 Subject: [PATCH 45/67] make pending crops unviewable to regular members --- app/controllers/crops_controller.rb | 2 ++ app/models/ability.rb | 2 +- app/models/crop.rb | 14 ++++++++------ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index 37316ad6a..30a570fc0 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -147,6 +147,8 @@ class CropsController < ApplicationController previous_status = @crop.approval_status + @crop.creator = current_member if previous_status == "pending" + respond_to do |format| if @crop.update(crop_params) if previous_status == "pending" diff --git a/app/models/ability.rb b/app/models/ability.rb index 8cf9a2efb..631a23d59 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -22,7 +22,7 @@ class Ability cannot :read, AccountType # and nobody should be able to view these expect admins and crop wranglers - cannot :read, Crop, :approval_status => "rejected" + cannot :read, Crop, :approval_status => ["rejected", "pending"] if member diff --git a/app/models/crop.rb b/app/models/crop.rb index a1ef6262c..c3fe377b8 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -21,14 +21,15 @@ class Crop < ActiveRecord::Base has_and_belongs_to_many :posts before_destroy {|crop| crop.posts.clear} - default_scope { where(:approval_status => "approved").order("lower(name) asc") } - scope :recent, -> { reorder("created_at desc") } - scope :toplevel, -> { where(:parent_id => nil) } - scope :popular, -> { reorder("plantings_count desc, lower(name) asc") } - scope :randomized, -> { reorder('random()') } # ok on sqlite and psql, but not on mysql + default_scope { order("lower(name) asc") } + scope :recent, -> { where(:approval_status => "approved").reorder("created_at desc") } + scope :toplevel, -> { where(:approval_status => "approved", :parent_id => nil) } + scope :popular, -> { where(:approval_status => "approved").reorder("plantings_count desc, lower(name) asc") } + scope :randomized, -> { where(:approval_status => "approved").reorder('random()') } # ok on sqlite and psql, but not on mysql scope :pending_approval, -> { where(:approval_status => "pending") } scope :rejected, -> { where(:approval_status => "rejected") } + ## Wikipedia urls are only necessary when approving a crop validates :en_wikipedia_url, :format => { :with => /\Ahttps?:\/\/en\.wikipedia\.org\/wiki/, @@ -36,8 +37,10 @@ class Crop < ActiveRecord::Base }, :if => :approved? + ## Reasons are only necessary when rejecting validates :reason_for_rejection, :presence => true, :if => :rejected? + ## This validation addresses a race condition validate :approval_status_cannot_be_changed_again def to_s @@ -237,7 +240,6 @@ class Crop < ActiveRecord::Base # Custom validations - # This validation addresses a race condition def approval_status_cannot_be_changed_again previous = previous_changes.include?(:approval_status) ? previous_changes.approval_status : {} if previous.include?(:rejected) || previous.include?(:approved) From b842bff9cbc968515f96f739d4ca60488c22f126 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Wed, 4 Feb 2015 18:36:14 +1100 Subject: [PATCH 46/67] wip: fix misc tests --- app/models/ability.rb | 3 +++ app/views/crops/wrangle.html.haml | 2 +- spec/factories/crop.rb | 1 + spec/features/crops/crop_wranglers_spec.rb | 22 +++++++++++++++++++- spec/features/crops/request_new_crop_spec.rb | 11 +--------- spec/views/crops/wrangle.html.haml_spec.rb | 2 +- 6 files changed, 28 insertions(+), 13 deletions(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index 631a23d59..ead008065 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -23,6 +23,9 @@ class Ability # and nobody should be able to view these expect admins and crop wranglers cannot :read, Crop, :approval_status => ["rejected", "pending"] + # # ... unless the current member is also the requester + # can :read, Crop, :requester_id => member.id + # can :read, Crop, :approval_status => "approved" if member diff --git a/app/views/crops/wrangle.html.haml b/app/views/crops/wrangle.html.haml index 933350ae6..a8576b543 100644 --- a/app/views/crops/wrangle.html.haml +++ b/app/views/crops/wrangle.html.haml @@ -37,7 +37,7 @@ = page_entries_info @crops, :model => "crops" = will_paginate @crops -%table#recently-added.table.table-striped +%table{:class => "table table-striped", :id => @approval_status.blank? ? 'recently-added-crops' : "#{@approval_status}-crops"} %tr %th System name %th English Wikipedia URL diff --git a/spec/factories/crop.rb b/spec/factories/crop.rb index 261979b45..4be8c4f09 100644 --- a/spec/factories/crop.rb +++ b/spec/factories/crop.rb @@ -66,6 +66,7 @@ FactoryGirl.define do factory :rejected_crop do name "Fail bean" + approval_status "rejected" reason_for_rejection "Totally fake" end diff --git a/spec/features/crops/crop_wranglers_spec.rb b/spec/features/crops/crop_wranglers_spec.rb index b01e3acc9..1b2af3f06 100644 --- a/spec/features/crops/crop_wranglers_spec.rb +++ b/spec/features/crops/crop_wranglers_spec.rb @@ -5,6 +5,8 @@ feature "crop wranglers" do let!(:crop_wranglers) { FactoryGirl.create_list(:crop_wrangling_member, 3) } let(:wrangler){crop_wranglers.first} let!(:crops) { FactoryGirl.create_list(:crop, 2) } + let!(:requested_crop) { FactoryGirl.create(:crop_request) } + let!(:rejected_crop) { FactoryGirl.create(:rejected_crop) } background do login_as(wrangler) @@ -25,7 +27,7 @@ feature "crop wranglers" do scenario "can see list of crops with extra detail of who created a crop" do visit root_path click_link 'Crop Wrangling' - within '#recently-added' do + within '#recently-added-crops' do expect(page).to have_content "#{crops.first.creator.login_name}" end end @@ -48,6 +50,24 @@ feature "crop wranglers" do expect(page).to have_content 'Crop was successfully created' expect(page).to have_content 'planticus maximus' end + + scenario "View pending crops" do + visit wrangle_crops_path(:approval_status => "pending") + within "#pending-crops" do + click_link "Ultra berry" + end + expect(page).to have_content "This crop is currently pending approval." + expect(page).to have_content "Please approve this even though it's fake." + end + + scenario "View rejected crops" do + visit wrangle_crops_path(:approval_status => "rejected") + within "#rejected-crops" do + click_link "Fail bean" + end + expect(page).to have_content "This crop was rejected for the following reason: Totally fake" + end + end diff --git a/spec/features/crops/request_new_crop_spec.rb b/spec/features/crops/request_new_crop_spec.rb index 49c52fc95..3ec8f502f 100644 --- a/spec/features/crops/request_new_crop_spec.rb +++ b/spec/features/crops/request_new_crop_spec.rb @@ -26,16 +26,6 @@ feature "Requesting a new crop" do before { login_as wrangler } - scenario "View pending crops" do - visit wrangle_crops_path - within "#requested-crops" do - expect(page).to have_content "Ultra berry" - end - click_link "Ultra berry" - expect(page).to have_content "This crop is currently pending approval." - expect(page).to have_content "Please approve this even though it's fake." - end - scenario "Approve a request" do visit edit_crop_path(crop) select "approved", from: "Approval Status" @@ -49,6 +39,7 @@ feature "Requesting a new crop" do scenario "Rejecting a crop" do visit edit_crop_path(crop) select "rejected", from: "Approval Status" + select "not edible", from: "Reason for rejection" click_button "Save" expect(page).to have_content "Crop was successfully updated." end diff --git a/spec/views/crops/wrangle.html.haml_spec.rb b/spec/views/crops/wrangle.html.haml_spec.rb index 24438899b..4426382d2 100644 --- a/spec/views/crops/wrangle.html.haml_spec.rb +++ b/spec/views/crops/wrangle.html.haml_spec.rb @@ -12,7 +12,7 @@ describe "crops/wrangle" do crops = WillPaginate::Collection.create(page, per_page, total_entries) do |pager| pager.replace([ @tomato, @maize ]) end - assign(:recent_crops, crops) + assign(:crops, crops) assign(:crop_wranglers, Role.crop_wranglers) end From 1099e4c9fe430d1a7585f996f3dea62360098377 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Fri, 6 Feb 2015 07:34:01 +1100 Subject: [PATCH 47/67] update copy for new / edit crop form --- app/views/crops/_form.html.haml | 17 ++++++++++++++--- app/views/crops/edit.html.haml | 2 +- app/views/crops/new.html.haml | 13 ++++++++++++- app/views/crops/show.html.haml | 2 +- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/app/views/crops/_form.html.haml b/app/views/crops/_form.html.haml index a58fab91c..9b2ee7a51 100644 --- a/app/views/crops/_form.html.haml +++ b/app/views/crops/_form.html.haml @@ -18,12 +18,21 @@ = f.label :name, :class => 'control-label col-md-2' .col-md-8 = f.text_field :name, :class => 'form-control' - %span.help-block Name in US English; singular; capitalize proper nouns only. + %span.help-block + - if can? :wrangle, @crop + Name in US English; singular; capitalize proper nouns only. + - else + Please provide the common name for the crop, in English, if you know it. + .form-group = f.label :en_wikipedia_url, 'Wikipedia URL', :class => 'control-label col-md-2' .col-md-8 = f.text_field :en_wikipedia_url, :class => 'form-control' - %span.help-block Link to this crop's page on the English language Wikipedia. + %span.help-block + - if can? :wrangle, @crop + Link to this crop's page on the English language Wikipedia. + - else + Please provide a link to the crop's page on the English language Wikipedia. Crops without Wikipedia pages cannot be added to our database at this time. - if can? :wrangle, @crop @@ -67,7 +76,9 @@ = f.label :request_notes, 'Comments', :class => 'control-label col-md-2' .col-md-8= f.text_area :request_notes, :rows => 6, :class => 'form-control' - + %p + %span.help-block + When you submit this form, your suggestion will be sent to our team of #{link_to 'volunteer crop wranglers', 'http://talk.growstuff.org/c/crop-wrangling'} for review. We'll let you know the outcome as soon as we can. .form-group .form-actions.col-md-offset-2.col-md-8 diff --git a/app/views/crops/edit.html.haml b/app/views/crops/edit.html.haml index 135f74a7c..dca7fb221 100644 --- a/app/views/crops/edit.html.haml +++ b/app/views/crops/edit.html.haml @@ -1,4 +1,4 @@ -- content_for :title, "Editing crop" +- content_for :title, "Review crop: #{@crop.name}" %p Added by diff --git a/app/views/crops/new.html.haml b/app/views/crops/new.html.haml index 63382ee95..fb4fcc5c3 100644 --- a/app/views/crops/new.html.haml +++ b/app/views/crops/new.html.haml @@ -1,3 +1,14 @@ -- content_for :title, "New crop" +- content_for :title, (can?(:wrangle, @crop) ? "New crop" : "Suggest a crop") + +- unless can? :wrangler, @crop + + %p Thanks for taking the time to suggest a crop! Our crop database is managed by volunteers, and we appreciate your help. Here are some things to consider when suggesting a new crop: + + %ul + %li First, you might want to search our crops to make sure we don't have it already, perhaps under an alternate name. + + %li The Growstuff database only contains edible crops. In future we hope to support other crops, but for now, if your suggestion is not edible we won't be able to add it. + + %li At this time, we are only adding crops which have a Wikipedia page. If you want to add a specific variety of crop that doesn't have its own Wikipedia entry, please use the more general form of the crop instead and put the name of your variety in the notes/description. = render 'form' diff --git a/app/views/crops/show.html.haml b/app/views/crops/show.html.haml index deadb5f05..7e8c94d9f 100644 --- a/app/views/crops/show.html.haml +++ b/app/views/crops/show.html.haml @@ -1,7 +1,7 @@ - content_for :title, @crop.name - content_for :subtitle, @crop.default_scientific_name -- if can?(:wrangle, @crop) && @crop.pending? +- if @crop.pending? .alert.alert-warning %b This crop is currently pending approval. %p This crop was requested by #{@crop.requester} on #{@crop.created_at}. From a69ad34359c9dd89f5f6279be2e620b06b0b80d8 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Fri, 6 Feb 2015 07:36:43 +1100 Subject: [PATCH 48/67] add link to search crops --- app/views/crops/new.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/crops/new.html.haml b/app/views/crops/new.html.haml index fb4fcc5c3..f472c4791 100644 --- a/app/views/crops/new.html.haml +++ b/app/views/crops/new.html.haml @@ -5,7 +5,7 @@ %p Thanks for taking the time to suggest a crop! Our crop database is managed by volunteers, and we appreciate your help. Here are some things to consider when suggesting a new crop: %ul - %li First, you might want to search our crops to make sure we don't have it already, perhaps under an alternate name. + %li First, you might want to #{link_to 'search our crops', crops_search_path} to make sure we don't have it already, perhaps under an alternate name. %li The Growstuff database only contains edible crops. In future we hope to support other crops, but for now, if your suggestion is not edible we won't be able to add it. From b78ccaa097b52d898295c9881bf83b93e7ac42e4 Mon Sep 17 00:00:00 2001 From: robertlandreaux Date: Fri, 6 Feb 2015 21:57:47 -0500 Subject: [PATCH 49/67] fix crop_wrangling_button_spec.rb --- app/views/crops/index.html.haml | 4 ++-- db/schema.rb | 1 - spec/features/crops/crop_wrangling_button_spec.rb | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/views/crops/index.html.haml b/app/views/crops/index.html.haml index 158bf965b..38ce986e0 100644 --- a/app/views/crops/index.html.haml +++ b/app/views/crops/index.html.haml @@ -1,7 +1,7 @@ - content_for :title, "Crops" - - if can? :wrangle, Crop - = link_to 'Wrangle Crops', wrangle_crops_path, :class => 'btn btn-primary' +- if can? :wrangle, Crop + = link_to 'Wrangle Crops', wrangle_crops_path, :class => 'btn btn-primary' %p #{ENV['GROWSTUFF_SITE_NAME']} tracks who's growing what, where. View any crop page to see which of our members have planted it and find diff --git a/db/schema.rb b/db/schema.rb index 2707a681e..92128a704 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -285,7 +285,6 @@ ActiveRecord::Schema.define(version: 20150201064502) do t.datetime "updated_at" t.string "slug" t.integer "forum_id" - t.integer "parent_id" end add_index "posts", ["created_at", "author_id"], name: "index_posts_on_created_at_and_author_id", using: :btree diff --git a/spec/features/crops/crop_wrangling_button_spec.rb b/spec/features/crops/crop_wrangling_button_spec.rb index 3acbedad4..26ef46e30 100644 --- a/spec/features/crops/crop_wrangling_button_spec.rb +++ b/spec/features/crops/crop_wrangling_button_spec.rb @@ -2,12 +2,12 @@ require 'rails_helper' feature "crop wrangling button" do - let(:crop_wrangling_member) { FactoryGirl.create(:crop_wrangler) } + let(:crop_wrangler) { FactoryGirl.create(:crop_wrangling_member) } context "crop wrangling button" do background do - login_as(:crop_wrangler) + login_as(crop_wrangler) visit crops_path end @@ -22,7 +22,7 @@ feature "crop wrangling button" do context "crop wrangling button" do background do - login_as(:member) + login_as(member) visit crops_path end From e6cbbb3e3da8c05999c9ac4698507e297f3afe5f Mon Sep 17 00:00:00 2001 From: Miles Gould Date: Sat, 7 Feb 2015 13:23:09 +0000 Subject: [PATCH 50/67] Use `fieldset` instead of abusing `.input-group`. As discussed in https://github.com/Growstuff/growstuff/pull/676#issuecomment-73072087 and following comments by @maco and @Skud. --- app/views/seeds/_form.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/seeds/_form.html.haml b/app/views/seeds/_form.html.haml index bb4528ee5..8d8eeaa97 100644 --- a/app/views/seeds/_form.html.haml +++ b/app/views/seeds/_form.html.haml @@ -23,7 +23,7 @@ = f.text_field :plant_before, :class => 'add-datepicker form-control', :value => @seed.plant_before ? @seed.plant_before.to_s(:ymd) : '' .form-group = f.label :days_until_maturity_min, 'Days until maturity:', :class => 'control-label col-md-2' - .input-group + %fieldset .col-md-2 = f.number_field :days_until_maturity_min, :class => 'form-control' .col-md-1 From c3429cc0f37437f9cd926491f88100a0b4c0aaee Mon Sep 17 00:00:00 2001 From: Mackenzie Morgan Date: Mon, 9 Feb 2015 00:05:02 -0500 Subject: [PATCH 51/67] adding admin access test for cms, and changing the cms admin path, and adding a link for it to the admin page, and updating the navbar so i can actually target the sign-in link in the test. also removing sample fixture gencode from cms installation --- app/views/admin/index.html.haml | 1 + app/views/layouts/_header.html.haml | 4 +- .../initializers/comfortable_mexican_sofa.rb | 2 +- config/routes.rb | 2 +- .../sample-site/categories/files.yml | 1 - .../sample-site/categories/pages.yml | 1 - .../sample-site/categories/snippets.yml | 1 - .../sample-site/files/_sample.jpg.yml | 5 --- db/cms_fixtures/sample-site/files/sample.jpg | Bin 6400 -> 0 bytes .../layouts/default/attributes.yml | 1 - .../sample-site/layouts/default/content.html | 5 --- .../sample-site/layouts/default/javascript.js | 1 - .../layouts/default/nested/attributes.yml | 2 - .../layouts/default/nested/content.haml | 3 -- .../layouts/default/nested/javascript.js | 1 - .../layouts/default/nested/stylesheet.css | 1 - .../layouts/default/stylesheet.css | 1 - .../sample-site/pages/index/attributes.yml | 6 --- .../pages/index/child/attributes.yml | 3 -- .../sample-site/pages/index/child/left.haml | 1 - .../sample-site/pages/index/child/right.html | 1 - .../pages/index/child/thumbnail.png | Bin 6600 -> 0 bytes .../sample-site/pages/index/content.html | 2 - .../snippets/default/attributes.yml | 4 -- .../sample-site/snippets/default/content.html | 1 - spec/features/cms_spec.rb | 37 ++++++++++++++++++ 26 files changed, 42 insertions(+), 45 deletions(-) delete mode 100644 db/cms_fixtures/sample-site/categories/files.yml delete mode 100644 db/cms_fixtures/sample-site/categories/pages.yml delete mode 100644 db/cms_fixtures/sample-site/categories/snippets.yml delete mode 100644 db/cms_fixtures/sample-site/files/_sample.jpg.yml delete mode 100644 db/cms_fixtures/sample-site/files/sample.jpg delete mode 100644 db/cms_fixtures/sample-site/layouts/default/attributes.yml delete mode 100644 db/cms_fixtures/sample-site/layouts/default/content.html delete mode 100644 db/cms_fixtures/sample-site/layouts/default/javascript.js delete mode 100644 db/cms_fixtures/sample-site/layouts/default/nested/attributes.yml delete mode 100644 db/cms_fixtures/sample-site/layouts/default/nested/content.haml delete mode 100644 db/cms_fixtures/sample-site/layouts/default/nested/javascript.js delete mode 100644 db/cms_fixtures/sample-site/layouts/default/nested/stylesheet.css delete mode 100644 db/cms_fixtures/sample-site/layouts/default/stylesheet.css delete mode 100644 db/cms_fixtures/sample-site/pages/index/attributes.yml delete mode 100644 db/cms_fixtures/sample-site/pages/index/child/attributes.yml delete mode 100644 db/cms_fixtures/sample-site/pages/index/child/left.haml delete mode 100644 db/cms_fixtures/sample-site/pages/index/child/right.html delete mode 100644 db/cms_fixtures/sample-site/pages/index/child/thumbnail.png delete mode 100644 db/cms_fixtures/sample-site/pages/index/content.html delete mode 100644 db/cms_fixtures/sample-site/snippets/default/attributes.yml delete mode 100644 db/cms_fixtures/sample-site/snippets/default/content.html create mode 100644 spec/features/cms_spec.rb diff --git a/app/views/admin/index.html.haml b/app/views/admin/index.html.haml index 18f0a043e..958ed39ed 100644 --- a/app/views/admin/index.html.haml +++ b/app/views/admin/index.html.haml @@ -8,6 +8,7 @@ %li= link_to "Roles", roles_path %li= link_to "Forums", forums_path %li= link_to "Newsletter subscribers", admin_newsletter_path + %li= link_to "CMS", comfy_admin_cms_path %h2 Orders diff --git a/app/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml index 691de3681..2e2c9f85a 100644 --- a/app/views/layouts/_header.html.haml +++ b/app/views/layouts/_header.html.haml @@ -65,8 +65,8 @@ %li= link_to "Sign out", destroy_member_session_path, :method => :delete - else - %li= link_to 'Sign in', new_member_session_path - %li= link_to 'Sign up', new_member_registration_path + %li= link_to 'Sign in', new_member_session_path, :id => 'navbar-signin' + %li= link_to 'Sign up', new_member_registration_path, :id => 'navbar-signup' = form_tag crops_search_path, :method => :get, :class => 'navbar-form pull-right' do .input diff --git a/config/initializers/comfortable_mexican_sofa.rb b/config/initializers/comfortable_mexican_sofa.rb index b70bc3afc..fe6e80ace 100644 --- a/config/initializers/comfortable_mexican_sofa.rb +++ b/config/initializers/comfortable_mexican_sofa.rb @@ -96,7 +96,7 @@ end module CmsDeviseAuth def authenticate - unless current_user && current_user.has_role?(:admin) + unless current_member && current_member.has_role?(:admin) redirect_to root_path, :alert => 'Permission denied. Please sign in as an admin user to use the CMS admin area.' end end diff --git a/config/routes.rb b/config/routes.rb index 8f4fa215b..69680ae2d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -86,7 +86,7 @@ Growstuff::Application.routes.draw do get '/admin/:action' => 'admin#:action' # CMS stuff -- must remain LAST - comfy_route :cms_admin, :path => '/cms' + comfy_route :cms_admin, :path => '/cms/admin' comfy_route :cms, :path => '/', :sitemap => false end diff --git a/db/cms_fixtures/sample-site/categories/files.yml b/db/cms_fixtures/sample-site/categories/files.yml deleted file mode 100644 index 2e59d3264..000000000 --- a/db/cms_fixtures/sample-site/categories/files.yml +++ /dev/null @@ -1 +0,0 @@ -- File Category \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/categories/pages.yml b/db/cms_fixtures/sample-site/categories/pages.yml deleted file mode 100644 index fec395558..000000000 --- a/db/cms_fixtures/sample-site/categories/pages.yml +++ /dev/null @@ -1 +0,0 @@ -- Page Category \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/categories/snippets.yml b/db/cms_fixtures/sample-site/categories/snippets.yml deleted file mode 100644 index a7d06fda6..000000000 --- a/db/cms_fixtures/sample-site/categories/snippets.yml +++ /dev/null @@ -1 +0,0 @@ -- Snippet Category \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/files/_sample.jpg.yml b/db/cms_fixtures/sample-site/files/_sample.jpg.yml deleted file mode 100644 index b978f0651..000000000 --- a/db/cms_fixtures/sample-site/files/_sample.jpg.yml +++ /dev/null @@ -1,5 +0,0 @@ -label: Fixture File -description: Fixture Description -categories: - - category_a - - category_b \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/files/sample.jpg b/db/cms_fixtures/sample-site/files/sample.jpg deleted file mode 100644 index 2b3a42b36a5c084bf1f701487a26aa533b6041e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6400 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 LhZIuX;naTt+W*7| diff --git a/db/cms_fixtures/sample-site/layouts/default/attributes.yml b/db/cms_fixtures/sample-site/layouts/default/attributes.yml deleted file mode 100644 index 6f1626b7c..000000000 --- a/db/cms_fixtures/sample-site/layouts/default/attributes.yml +++ /dev/null @@ -1 +0,0 @@ -label: Default Fixture Layout \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/layouts/default/content.html b/db/cms_fixtures/sample-site/layouts/default/content.html deleted file mode 100644 index f2707392b..000000000 --- a/db/cms_fixtures/sample-site/layouts/default/content.html +++ /dev/null @@ -1,5 +0,0 @@ - - - {{ cms:page:content }} - - \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/layouts/default/javascript.js b/db/cms_fixtures/sample-site/layouts/default/javascript.js deleted file mode 100644 index 6959d8bfc..000000000 --- a/db/cms_fixtures/sample-site/layouts/default/javascript.js +++ /dev/null @@ -1 +0,0 @@ -// default js \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/layouts/default/nested/attributes.yml b/db/cms_fixtures/sample-site/layouts/default/nested/attributes.yml deleted file mode 100644 index 754f082c4..000000000 --- a/db/cms_fixtures/sample-site/layouts/default/nested/attributes.yml +++ /dev/null @@ -1,2 +0,0 @@ -label: Default Fixture Nested Layout -position: 42 \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/layouts/default/nested/content.haml b/db/cms_fixtures/sample-site/layouts/default/nested/content.haml deleted file mode 100644 index 2f09fd402..000000000 --- a/db/cms_fixtures/sample-site/layouts/default/nested/content.haml +++ /dev/null @@ -1,3 +0,0 @@ -{{ cms:page_file:thumbnail:url }} -.left {{ cms:page:left }} -.right {{ cms:page:right }} \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/layouts/default/nested/javascript.js b/db/cms_fixtures/sample-site/layouts/default/nested/javascript.js deleted file mode 100644 index 2508c22ed..000000000 --- a/db/cms_fixtures/sample-site/layouts/default/nested/javascript.js +++ /dev/null @@ -1 +0,0 @@ -// nested js \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/layouts/default/nested/stylesheet.css b/db/cms_fixtures/sample-site/layouts/default/nested/stylesheet.css deleted file mode 100644 index 034f6fb9c..000000000 --- a/db/cms_fixtures/sample-site/layouts/default/nested/stylesheet.css +++ /dev/null @@ -1 +0,0 @@ -div{float:left} \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/layouts/default/stylesheet.css b/db/cms_fixtures/sample-site/layouts/default/stylesheet.css deleted file mode 100644 index cd8b4f19d..000000000 --- a/db/cms_fixtures/sample-site/layouts/default/stylesheet.css +++ /dev/null @@ -1 +0,0 @@ -body{color: red} \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/pages/index/attributes.yml b/db/cms_fixtures/sample-site/pages/index/attributes.yml deleted file mode 100644 index 56616f972..000000000 --- a/db/cms_fixtures/sample-site/pages/index/attributes.yml +++ /dev/null @@ -1,6 +0,0 @@ -label: Home Fixture Page -layout: default -target_page: '/child' -categories: - - category_a - - category_b \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/pages/index/child/attributes.yml b/db/cms_fixtures/sample-site/pages/index/child/attributes.yml deleted file mode 100644 index d8602e148..000000000 --- a/db/cms_fixtures/sample-site/pages/index/child/attributes.yml +++ /dev/null @@ -1,3 +0,0 @@ -label: Child Fixture Page -layout: nested -position: 42 diff --git a/db/cms_fixtures/sample-site/pages/index/child/left.haml b/db/cms_fixtures/sample-site/pages/index/child/left.haml deleted file mode 100644 index 756907e5e..000000000 --- a/db/cms_fixtures/sample-site/pages/index/child/left.haml +++ /dev/null @@ -1 +0,0 @@ -= "Child Page Left Fixture Content" \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/pages/index/child/right.html b/db/cms_fixtures/sample-site/pages/index/child/right.html deleted file mode 100644 index 3ac08e9ab..000000000 --- a/db/cms_fixtures/sample-site/pages/index/child/right.html +++ /dev/null @@ -1 +0,0 @@ -Child Page Right Fixture Content \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/pages/index/child/thumbnail.png b/db/cms_fixtures/sample-site/pages/index/child/thumbnail.png deleted file mode 100644 index 89cf33f55ee298e089b39c4aab4a0e62fdfc065b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6600 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 O#sSwd)GUM9h5rvhyEdc% diff --git a/db/cms_fixtures/sample-site/pages/index/content.html b/db/cms_fixtures/sample-site/pages/index/content.html deleted file mode 100644 index fb97a42a7..000000000 --- a/db/cms_fixtures/sample-site/pages/index/content.html +++ /dev/null @@ -1,2 +0,0 @@ -Home Page Fixture Contént -{{ cms:snippet:default }} \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/snippets/default/attributes.yml b/db/cms_fixtures/sample-site/snippets/default/attributes.yml deleted file mode 100644 index 2113c3ce6..000000000 --- a/db/cms_fixtures/sample-site/snippets/default/attributes.yml +++ /dev/null @@ -1,4 +0,0 @@ -label: Default Fixture Snippet -categories: - - category_a - - category_b \ No newline at end of file diff --git a/db/cms_fixtures/sample-site/snippets/default/content.html b/db/cms_fixtures/sample-site/snippets/default/content.html deleted file mode 100644 index 48a4995fa..000000000 --- a/db/cms_fixtures/sample-site/snippets/default/content.html +++ /dev/null @@ -1 +0,0 @@ -Fixture Content for Default Snippet \ No newline at end of file diff --git a/spec/features/cms_spec.rb b/spec/features/cms_spec.rb new file mode 100644 index 000000000..fb3f2ca93 --- /dev/null +++ b/spec/features/cms_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +feature "cms admin" do + before(:each) do + @member = FactoryGirl.create(:member) + @admin_member = FactoryGirl.create(:admin_member) + end + + scenario "can't view CMS admin if not signed in" do + visit comfy_admin_cms_path + current_path.should == root_path + page.should have_content("Please sign in as an admin user") + end + + scenario "can't view CMS admin if not an admin member" do + # sign in as an ordinary member + visit root_path + click_link 'navbar-signin' + fill_in 'Login', :with => @member.email + fill_in 'Password', :with => @member.password + click_button 'Sign in' + visit comfy_admin_cms_path + current_path.should == root_path + page.should have_content("Please sign in as an admin user") + end + + scenario "admin members can view CMS admin area" do + visit root_path + # now we sign in as an admin member + click_link 'navbar-signin' + fill_in 'Login', :with => @admin_member.email + fill_in 'Password', :with => @admin_member.password + click_button 'Sign in' + visit comfy_admin_cms_path + current_path.should match /#{comfy_admin_cms_path}/ # match any CMS admin page + end +end From 49a5a26f17816113003588f4dc567fd9751dcfb9 Mon Sep 17 00:00:00 2001 From: Savant Krishna Date: Tue, 3 Feb 2015 20:49:30 +1100 Subject: [PATCH 52/67] Functionality to sort members by recently joined : Issue #550 --- app/controllers/members_controller.rb | 7 +++++- app/models/member.rb | 1 + app/views/members/index.html.haml | 6 +++++ spec/features/members_list_spec.rb | 35 +++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 spec/features/members_list_spec.rb diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb index 8ca1c4c24..744e93f4c 100644 --- a/app/controllers/members_controller.rb +++ b/app/controllers/members_controller.rb @@ -6,7 +6,12 @@ class MembersController < ApplicationController after_action :expire_cache_fragments, :only => :create def index - @members = Member.confirmed.paginate(:page => params[:page]) + @sort = params[:sort] + if @sort == 'recently_joined' + @members = Member.confirmed.recently_joined.paginate(:page => params[:page]) + else + @members = Member.confirmed.paginate(:page => params[:page]) + end respond_to do |format| format.html # index.html.haml diff --git a/app/models/member.rb b/app/models/member.rb index f23e7e45f..6c00fb8ce 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -32,6 +32,7 @@ class Member < ActiveRecord::Base scope :confirmed, -> { where('confirmed_at IS NOT NULL') } scope :located, -> { where("location <> '' and latitude IS NOT NULL and longitude IS NOT NULL") } scope :recently_signed_in, -> { reorder('updated_at DESC') } + scope :recently_joined, -> { reorder("confirmed_at desc") } scope :wants_newsletter, -> { where(:newsletter => true) } has_many :follows, :class_name => "Follow", :foreign_key => "follower_id" diff --git a/app/views/members/index.html.haml b/app/views/members/index.html.haml index 83a663d47..36ba70887 100644 --- a/app/views/members/index.html.haml +++ b/app/views/members/index.html.haml @@ -1,5 +1,11 @@ = content_for :title, "#{ENV['GROWSTUFF_SITE_NAME']} members" += form_tag(members_path, :method => :get, :class => 'form-inline', :role => 'form') do + .form-group + = label_tag :sort, "Sort by:", :class => 'sr-only' + = select_tag "sort", options_for_select({"Sort alphabetically" => 'alpha', "Sort by recently joined" => "recently_joined"}, @sort || 'alpha'), :class => 'form-control' + = submit_tag "Show", :class => 'btn btn-primary' + %div.pagination = page_entries_info @members, :model => "members" = will_paginate @members diff --git a/spec/features/members_list_spec.rb b/spec/features/members_list_spec.rb new file mode 100644 index 000000000..68cbb6d1f --- /dev/null +++ b/spec/features/members_list_spec.rb @@ -0,0 +1,35 @@ +require 'rails_helper' + +feature "members list" do + + context "list all members" do + let! (:member1) { FactoryGirl.create(:member, :login_name => "Archaeopteryx", :confirmed_at => Time.zone.parse('2013-02-10')) } + let! (:member2) { FactoryGirl.create(:member, :login_name => "Zephyrosaurus", :confirmed_at => Time.zone.parse('2014-01-11')) } + let! (:member3) { FactoryGirl.create(:member, :login_name => "Testingname", :confirmed_at => Time.zone.parse('2014-05-09')) } + + scenario "default alphabetical sort" do + visit members_path + expect(page).to have_css "#sort" + expect(page).to have_selector "form" + click_button('Show') + all_links = page.all("#maincontainer p") + expect(all_links.first).to have_text member1.login_name + expect(all_links.last).to have_text member2.login_name + end + + scenario "recently joined sort" do + visit members_path + expect(page).to have_css "#sort" + expect(page).to have_selector "form" + select("recently", :from => 'sort') + click_button('Show') + all_links = page.all("#maincontainer p") + expect(all_links.first).to have_text member3.login_name + expect(all_links.last).to have_text member1.login_name + + end + + + end + +end From e17a3a2ab1b2488780e99b097885c870614d7ef5 Mon Sep 17 00:00:00 2001 From: Savant Krishna Date: Mon, 9 Feb 2015 17:35:17 +1100 Subject: [PATCH 53/67] Addition to Contributors list --- CONTRIBUTORS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 60a69a272..ad76d09fa 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -53,3 +53,5 @@ submit the change with your pull request. - Justin Hamman / [juzham](https://github.com/juzham) - Rocky Jaiswal / [rocky-jaiswal](https://github.com/rocky-jaiswal) - Robert Landreaux / [robertlandreaux](https://github.com/robertlandreaux) +- Savant Krishna / [sksavant](https://github.com/sksavant) + From 2db7bf638bc30b624ede83d1e6a55895cdbe3111 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Mon, 9 Feb 2015 20:41:28 +1100 Subject: [PATCH 54/67] improve copy for new request email --- app/controllers/crops_controller.rb | 2 +- app/mailers/notifier.rb | 2 +- app/views/notifier/new_crop_request.html.haml | 23 ++++++++++++++++--- db/schema.rb | 1 + 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index 19f55d7ef..2c64f5cc8 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -123,7 +123,7 @@ class CropsController < ApplicationController respond_to do |format| if @crop.save - if current_member.has_role? :crop_wrangler + unless current_member.has_role? :crop_wrangler Role.crop_wranglers.each do |w| Notifier.new_crop_request(w, @crop).deliver! end diff --git a/app/mailers/notifier.rb b/app/mailers/notifier.rb index 88c5f50f5..53bae3092 100644 --- a/app/mailers/notifier.rb +++ b/app/mailers/notifier.rb @@ -24,7 +24,7 @@ class Notifier < ActionMailer::Base def new_crop_request(member, request) @member, @request = member, request - mail(:to => @member.email, :subject => "New crop request") + mail(:to => @member.email, :subject => "#{@request.requester.login_name} has requested #{@request.name} as a new crop") end def crop_request_approved(member, crop) diff --git a/app/views/notifier/new_crop_request.html.haml b/app/views/notifier/new_crop_request.html.haml index 2fc16df7d..26b63f8ff 100644 --- a/app/views/notifier/new_crop_request.html.haml +++ b/app/views/notifier/new_crop_request.html.haml @@ -1,7 +1,24 @@ - site_name = ENV['GROWSTUFF_SITE_NAME'] + %p Hello #{@member.login_name}, -%p - A new crop has been requested. View, edit, approve or reject the request: +%p + #{@request.requester.login_name} has requested a new crop on #{site_name}. - = link_to "Request for #{@request}", crop_url(@request) +%ul + %li Name: #{@request.name} + %li Wikipedia URL: #{@request.en_wikipedia_url.present? ? @request.en_wikipedia_url : "not specified"} + +%p + As a crop wrangler, you can #{link_to "approve or reject this request", edit_crop_url(@request)}. + +%p + Or, discuss this and other crop wrangling issues in our #{link_to "crop wrangling forum", "http://talk.growstuff.org/c/crop-wrangling"}. + +%p + Thanks for your help! + +%p + The Growstuff (staging) team + %br/ + =link_to root_url, root_url \ No newline at end of file diff --git a/db/schema.rb b/db/schema.rb index ebafd6fa2..4d3f407b9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -285,6 +285,7 @@ ActiveRecord::Schema.define(version: 20150201064502) do t.datetime "updated_at" t.string "slug" t.integer "forum_id" + t.integer "parent_id" end add_index "posts", ["created_at", "author_id"], name: "index_posts_on_created_at_and_author_id", using: :btree From 319fc12ebb31cc4d03162fbaee5e9f91f5316572 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Mon, 9 Feb 2015 21:13:25 +1100 Subject: [PATCH 55/67] add crop must be approved validation --- app/models/harvest.rb | 2 ++ app/models/planting.rb | 2 ++ app/models/seed.rb | 2 ++ app/validators/approved_validator.rb | 7 +++++++ app/views/crops/show.html.haml | 19 ++++++++++--------- 5 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 app/validators/approved_validator.rb diff --git a/app/models/harvest.rb b/app/models/harvest.rb index edd16ee55..4339a30fa 100644 --- a/app/models/harvest.rb +++ b/app/models/harvest.rb @@ -20,6 +20,8 @@ class Harvest < ActiveRecord::Base default_scope { order('created_at DESC') } + validates :crop, :approved => true + validates :crop, :presence => {:message => "must be present and exist in our database"} validates :quantity, diff --git a/app/models/planting.rb b/app/models/planting.rb index 592ef1681..aa3287bf9 100644 --- a/app/models/planting.rb +++ b/app/models/planting.rb @@ -30,6 +30,8 @@ class Planting < ActiveRecord::Base default_scope { order("created_at desc") } + validates :crop, :approved => true + validates :crop_id, :presence => {:message => "must be present and exist in our database"} validates :quantity, diff --git a/app/models/seed.rb b/app/models/seed.rb index cae7402d9..9fa005907 100644 --- a/app/models/seed.rb +++ b/app/models/seed.rb @@ -7,6 +7,8 @@ class Seed < ActiveRecord::Base default_scope { order("created_at desc") } + validates :crop, :approved => true + validates :crop, :presence => {:message => "must be present and exist in our database"} validates :quantity, :numericality => { diff --git a/app/validators/approved_validator.rb b/app/validators/approved_validator.rb new file mode 100644 index 000000000..513bc25bd --- /dev/null +++ b/app/validators/approved_validator.rb @@ -0,0 +1,7 @@ +class ApprovedValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + unless value.approved? + record.errors[attribute] << (options[:message] || 'must be approved') + end + end +end diff --git a/app/views/crops/show.html.haml b/app/views/crops/show.html.haml index 7e8c94d9f..e623d6bf4 100644 --- a/app/views/crops/show.html.haml +++ b/app/views/crops/show.html.haml @@ -2,7 +2,7 @@ - content_for :subtitle, @crop.default_scientific_name - if @crop.pending? - .alert.alert-warning + .alert.alert-danger %b This crop is currently pending approval. %p This crop was requested by #{@crop.requester} on #{@crop.created_at}. - unless @crop.request_notes.blank? @@ -10,18 +10,19 @@ Request notes: #{@crop.request_notes} - if @crop.rejected? - .alert.alert-warning + .alert.alert-danger %b This crop was rejected for the following reason: #{@crop.reason_for_rejection}. -- content_for :buttonbar do - - if can? :create, Planting - = link_to "Plant this", new_planting_path(:crop_id => @crop.id), :class => 'btn btn-default' +- if @crop.approved? + - content_for :buttonbar do + - if can? :create, Planting + = link_to "Plant this", new_planting_path(:crop_id => @crop.id), :class => 'btn btn-default' - - if can? :create, Harvest - = link_to "Harvest this", new_harvest_path(:crop_id => @crop.id), :class => 'btn btn-default' + - if can? :create, Harvest + = link_to "Harvest this", new_harvest_path(:crop_id => @crop.id), :class => 'btn btn-default' - - if can? :create, Seed - = link_to 'Add seeds to stash', new_seed_path(:params => { :crop_id => @crop.id }), :class => 'btn btn-default' + - if can? :create, Seed + = link_to 'Add seeds to stash', new_seed_path(:params => { :crop_id => @crop.id }), :class => 'btn btn-default' .row From 0dbc2e1964f9cf3eb4889e80a1bcdd82357ae11a Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Mon, 9 Feb 2015 21:52:52 +1100 Subject: [PATCH 56/67] prevent users from seeing sci names of crops unless approved --- app/models/ability.rb | 5 +++++ app/views/crops/wrangle.html.haml | 22 +++++++++------------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index ff5fe4994..f78fdfcbf 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -25,6 +25,11 @@ class Ability # are wranglers or admins cannot :read, Crop can :read, Crop, :approval_status => "approved" + # scientific names should only be viewable if associated crop is approved + cannot :read, ScientificName + can :read, ScientificName do |sn| + sn.crop.approved? + end if member # members can see even rejected or pending crops if they requested it diff --git a/app/views/crops/wrangle.html.haml b/app/views/crops/wrangle.html.haml index a8576b543..549a737a1 100644 --- a/app/views/crops/wrangle.html.haml +++ b/app/views/crops/wrangle.html.haml @@ -18,7 +18,7 @@ .tabbable %ul.nav.nav-tabs %li{:class => @approval_status.blank? ? 'active' : ''} - = link_to "Recendly added", wrangle_crops_path + = link_to "Recently added", wrangle_crops_path %li{:class => @approval_status == "pending" ? 'active' : ''} = link_to "Pending approval", wrangle_crops_path(:approval_status => "pending") %li{:class => @approval_status == "rejected" ? 'active' : ''} @@ -42,13 +42,11 @@ %th System name %th English Wikipedia URL %th Scientific names - %th - - if @approval_status == "pending" - Requested by - - elsif @approval_status == "rejected" - Rejected by - - else - Added by + %th Requested by + - if @approval_status == "rejected" + %th Rejected by + - if @approval_status != "rejected" && @approval_status != "pending" + %th Added by %th When - @crops.each do |c| %tr @@ -58,11 +56,9 @@ - c.scientific_names.each do |s| = link_to s.scientific_name, s %br/ - %td - - if @approval_status == "pending" - = link_to c.requester, c.requester - - else - = link_to c.creator, c.creator + %td= c.requester.present? ? (link_to c.requester, c.requester) : "N/A" + - unless @approval_status == "pending" + %td= c.creator.present? ? (link_to c.creator, c.creator) : "N/A" %td = distance_of_time_in_words(c.created_at, Time.zone.now) ago. From cbb4f9d7ac0c2e8668aff8792c9440605478520a Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Mon, 9 Feb 2015 22:17:32 +1100 Subject: [PATCH 57/67] add rejection notes --- app/controllers/crops_controller.rb | 6 +++++- app/models/crop.rb | 18 ++++++++++++++++++ app/views/crops/_form.html.haml | 9 +++++++++ app/views/crops/show.html.haml | 4 ++-- ...50209105410_add_rejection_notes_to_crops.rb | 5 +++++ db/schema.rb | 3 ++- 6 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20150209105410_add_rejection_notes_to_crops.rb diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index 2c64f5cc8..9fd302669 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -105,6 +105,10 @@ class CropsController < ApplicationController # GET /crops/1/edit def edit @crop = Crop.find(params[:id]) + + (3 - @crop.scientific_names.length).times do + @crop.scientific_names.build + end end # POST /crops @@ -179,6 +183,6 @@ class CropsController < ApplicationController private def crop_params - params.require(:crop).permit(:en_wikipedia_url, :name, :parent_id, :creator_id, :approval_status, :request_notes, :reason_for_rejection, :scientific_names_attributes => [:scientific_name, :_destroy, :id]) + params.require(:crop).permit(:en_wikipedia_url, :name, :parent_id, :creator_id, :approval_status, :request_notes, :reason_for_rejection, :rejection_notes, :scientific_names_attributes => [:scientific_name, :_destroy, :id]) end end diff --git a/app/models/crop.rb b/app/models/crop.rb index 905af8562..f11d78567 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -43,6 +43,10 @@ class Crop < ActiveRecord::Base ## This validation addresses a race condition validate :approval_status_cannot_be_changed_again + validate :must_be_rejected_if_rejected_reasons_present + + validate :must_have_meaningful_reason_for_rejection + #################################### # Elastic search configuration include Elasticsearch::Model @@ -324,4 +328,18 @@ class Crop < ActiveRecord::Base end end + def must_be_rejected_if_rejected_reasons_present + unless rejected? + if reason_for_rejection.present? || rejection_notes.present? + errors.add(:approval_status, "must be rejected if a reason for rejection is present") + end + end + end + + def must_have_meaningful_reason_for_rejection + if reason_for_rejection == "other" && rejection_notes.blank? + errors.add(:rejection_notes, "must be added if the reason for rejection is \"other\"") + end + end + end diff --git a/app/views/crops/_form.html.haml b/app/views/crops/_form.html.haml index 9b2ee7a51..6a2d9f562 100644 --- a/app/views/crops/_form.html.haml +++ b/app/views/crops/_form.html.haml @@ -56,6 +56,8 @@ = sn.check_box :_destroy = sn.label :_destroy, "Delete" + %hr / + - unless @crop.new_record? .form-group = f.label :approval_status, 'Approval Status', :class=> 'control-label col-md-2' @@ -66,6 +68,13 @@ = f.label :reason_for_rejection, 'Reason for rejection', :class => 'control-label col-md-2' .col-md-8 = f.select(:reason_for_rejection, @crop.reasons_for_rejection, {:include_blank => true}, {:class => 'form-control'}) + %p + %span.help-block + Please provide additional notes why this crop request was rejected if the above reasons do not apply. + + .form-group + = f.label :rejection_notes, 'Rejection Notes', :class => 'control-label col-md-2' + .col-md-8= f.text_area :rejection_notes, :rows => 6, :class => 'form-control' - else %p diff --git a/app/views/crops/show.html.haml b/app/views/crops/show.html.haml index e623d6bf4..bda1804d2 100644 --- a/app/views/crops/show.html.haml +++ b/app/views/crops/show.html.haml @@ -4,14 +4,14 @@ - if @crop.pending? .alert.alert-danger %b This crop is currently pending approval. - %p This crop was requested by #{@crop.requester} on #{@crop.created_at}. + %p This crop was requested by #{@crop.requester} #{time_ago_in_words(@crop.created_at)} ago. - unless @crop.request_notes.blank? %p Request notes: #{@crop.request_notes} - if @crop.rejected? .alert.alert-danger - %b This crop was rejected for the following reason: #{@crop.reason_for_rejection}. + %b This crop was rejected for the following reason: #{@crop.reason_for_rejection == "other" ? @crop.rejection_notes : @crop.reason_for_rejection}. - if @crop.approved? - content_for :buttonbar do diff --git a/db/migrate/20150209105410_add_rejection_notes_to_crops.rb b/db/migrate/20150209105410_add_rejection_notes_to_crops.rb new file mode 100644 index 000000000..59239fd55 --- /dev/null +++ b/db/migrate/20150209105410_add_rejection_notes_to_crops.rb @@ -0,0 +1,5 @@ +class AddRejectionNotesToCrops < ActiveRecord::Migration + def change + add_column :crops, :rejection_notes, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 4d3f407b9..aca632ccf 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150201064502) do +ActiveRecord::Schema.define(version: 20150209105410) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -74,6 +74,7 @@ ActiveRecord::Schema.define(version: 20150201064502) do t.string "approval_status", default: "approved" t.text "reason_for_rejection" t.text "request_notes" + t.text "rejection_notes" end add_index "crops", ["name"], name: "index_crops_on_name", using: :btree From 2697fea24982c0b824db3139d7cc9062c3d0ee36 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Mon, 9 Feb 2015 22:41:35 +1100 Subject: [PATCH 58/67] tests back to green --- app/validators/approved_validator.rb | 2 +- app/views/crops/_form.html.haml | 2 -- spec/features/crops/request_new_crop_spec.rb | 1 + spec/mailers/notifier_spec.rb | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/validators/approved_validator.rb b/app/validators/approved_validator.rb index 513bc25bd..4016058aa 100644 --- a/app/validators/approved_validator.rb +++ b/app/validators/approved_validator.rb @@ -1,6 +1,6 @@ class ApprovedValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) - unless value.approved? + unless record.crop.try(:approved?) record.errors[attribute] << (options[:message] || 'must be approved') end end diff --git a/app/views/crops/_form.html.haml b/app/views/crops/_form.html.haml index 6a2d9f562..e7be7cd62 100644 --- a/app/views/crops/_form.html.haml +++ b/app/views/crops/_form.html.haml @@ -56,8 +56,6 @@ = sn.check_box :_destroy = sn.label :_destroy, "Delete" - %hr / - - unless @crop.new_record? .form-group = f.label :approval_status, 'Approval Status', :class=> 'control-label col-md-2' diff --git a/spec/features/crops/request_new_crop_spec.rb b/spec/features/crops/request_new_crop_spec.rb index 66e996d66..0a1cac2a7 100644 --- a/spec/features/crops/request_new_crop_spec.rb +++ b/spec/features/crops/request_new_crop_spec.rb @@ -5,6 +5,7 @@ feature "Requesting a new crop" do context "As a regular member" do let(:member) { FactoryGirl.create(:member) } + let!(:wrangler) { FactoryGirl.create(:crop_wrangling_member) } before { login_as member } diff --git a/spec/mailers/notifier_spec.rb b/spec/mailers/notifier_spec.rb index 4ad7bd53c..ce552f99b 100644 --- a/spec/mailers/notifier_spec.rb +++ b/spec/mailers/notifier_spec.rb @@ -52,7 +52,7 @@ describe Notifier do let(:mail) { Notifier.new_crop_request(member, crop) } it 'sets the subject correctly' do - mail.subject.should == "New crop request" + mail.subject.should == "#{crop.requester.login_name} has requested Ultra berry as a new crop" end it 'comes from noreply@growstuff.org' do From 07f7572b13352203eefe9aad4b32abc0529e5bc3 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Tue, 10 Feb 2015 18:33:54 +1100 Subject: [PATCH 59/67] extract email signature into partial --- app/views/notifier/_signature.html.haml | 4 ++++ app/views/notifier/crop_request_approved.html.haml | 3 +++ app/views/notifier/crop_request_rejected.html.haml | 4 +++- app/views/notifier/new_crop_request.html.haml | 5 +---- app/views/notifier/notify.html.haml | 5 +---- app/views/notifier/planting_reminder.html.haml | 5 +---- 6 files changed, 13 insertions(+), 13 deletions(-) create mode 100644 app/views/notifier/_signature.html.haml diff --git a/app/views/notifier/_signature.html.haml b/app/views/notifier/_signature.html.haml new file mode 100644 index 000000000..30101610d --- /dev/null +++ b/app/views/notifier/_signature.html.haml @@ -0,0 +1,4 @@ +%p + The #{site_name} team. + %br/ + =link_to root_url, root_url diff --git a/app/views/notifier/crop_request_approved.html.haml b/app/views/notifier/crop_request_approved.html.haml index 5fe184f1a..5fea20246 100644 --- a/app/views/notifier/crop_request_approved.html.haml +++ b/app/views/notifier/crop_request_approved.html.haml @@ -11,3 +11,6 @@ = link_to "Harvest #{@crop.name}", new_harvest_url(crop_id: @crop.id) %li = link_to "Stash seeds for #{@crop.name}", new_seed_url(crop_id: @crop.id) + += render :partial => 'signature' + diff --git a/app/views/notifier/crop_request_rejected.html.haml b/app/views/notifier/crop_request_rejected.html.haml index 315f7036d..2d14b04d8 100644 --- a/app/views/notifier/crop_request_rejected.html.haml +++ b/app/views/notifier/crop_request_rejected.html.haml @@ -4,4 +4,6 @@ %p Your request for the new crop: #{link_to @crop.name, crop_url(@crop)} has been rejected for the following reason. - = @crop.reason_for_rejection \ No newline at end of file + = @crop.reason_for_rejection + += render :partial => 'signature' diff --git a/app/views/notifier/new_crop_request.html.haml b/app/views/notifier/new_crop_request.html.haml index 26b63f8ff..c794e7ece 100644 --- a/app/views/notifier/new_crop_request.html.haml +++ b/app/views/notifier/new_crop_request.html.haml @@ -18,7 +18,4 @@ %p Thanks for your help! -%p - The Growstuff (staging) team - %br/ - =link_to root_url, root_url \ No newline at end of file += render :partial => 'signature' diff --git a/app/views/notifier/notify.html.haml b/app/views/notifier/notify.html.haml index b6e962fb3..ed9cf32f2 100644 --- a/app/views/notifier/notify.html.haml +++ b/app/views/notifier/notify.html.haml @@ -20,7 +20,4 @@ %br/ = link_to "Turn off these notifications", edit_member_registration_url -%p - The #{site_name} team. - %br/ - =link_to root_url, root_url += render :partial => 'signature' \ No newline at end of file diff --git a/app/views/notifier/planting_reminder.html.haml b/app/views/notifier/planting_reminder.html.haml index 7edf063b5..4dea05123 100644 --- a/app/views/notifier/planting_reminder.html.haml +++ b/app/views/notifier/planting_reminder.html.haml @@ -59,10 +59,7 @@ %h2 See you soon on #{site_name}! -%p - The #{site_name} team. - %br/ - =link_to root_url, root_url += render :partial => 'signature' %hr/ %p From b81e0342545dc7ee1639c3b40761f611857838ba Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Tue, 10 Feb 2015 18:38:32 +1100 Subject: [PATCH 60/67] tweak permissions for alternate names just like sci names --- app/models/ability.rb | 5 +++++ app/models/planting.rb | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index f78fdfcbf..1997ddf49 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -30,6 +30,11 @@ class Ability can :read, ScientificName do |sn| sn.crop.approved? end + # ... same for alternate names + cannot :read, AlternateName + can :read, AlternateName do |an| + an.crop.approved? + end if member # members can see even rejected or pending crops if they requested it diff --git a/app/models/planting.rb b/app/models/planting.rb index aa3287bf9..958ba625f 100644 --- a/app/models/planting.rb +++ b/app/models/planting.rb @@ -32,7 +32,7 @@ class Planting < ActiveRecord::Base validates :crop, :approved => true - validates :crop_id, :presence => {:message => "must be present and exist in our database"} + validates :crop, :presence => {:message => "must be present and exist in our database"} validates :quantity, :numericality => { From c61f7b8e72ca045f88f0a129f2a546d90a06f448 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Tue, 10 Feb 2015 18:52:24 +1100 Subject: [PATCH 61/67] pass locals into signature partial properly --- app/views/notifier/crop_request_approved.html.haml | 2 +- app/views/notifier/crop_request_rejected.html.haml | 2 +- app/views/notifier/new_crop_request.html.haml | 2 +- app/views/notifier/notify.html.haml | 2 +- app/views/notifier/planting_reminder.html.haml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/notifier/crop_request_approved.html.haml b/app/views/notifier/crop_request_approved.html.haml index 5fea20246..95a1da688 100644 --- a/app/views/notifier/crop_request_approved.html.haml +++ b/app/views/notifier/crop_request_approved.html.haml @@ -12,5 +12,5 @@ %li = link_to "Stash seeds for #{@crop.name}", new_seed_url(crop_id: @crop.id) -= render :partial => 'signature' += render :partial => 'signature', :locals => { :site_name => site_name } diff --git a/app/views/notifier/crop_request_rejected.html.haml b/app/views/notifier/crop_request_rejected.html.haml index 2d14b04d8..578eb5bc5 100644 --- a/app/views/notifier/crop_request_rejected.html.haml +++ b/app/views/notifier/crop_request_rejected.html.haml @@ -6,4 +6,4 @@ = @crop.reason_for_rejection -= render :partial => 'signature' += render :partial => 'signature', :locals => { :site_name => site_name } \ No newline at end of file diff --git a/app/views/notifier/new_crop_request.html.haml b/app/views/notifier/new_crop_request.html.haml index c794e7ece..395ad2741 100644 --- a/app/views/notifier/new_crop_request.html.haml +++ b/app/views/notifier/new_crop_request.html.haml @@ -18,4 +18,4 @@ %p Thanks for your help! -= render :partial => 'signature' += render :partial => 'signature', :locals => { :site_name => site_name } \ No newline at end of file diff --git a/app/views/notifier/notify.html.haml b/app/views/notifier/notify.html.haml index ed9cf32f2..7260d84be 100644 --- a/app/views/notifier/notify.html.haml +++ b/app/views/notifier/notify.html.haml @@ -20,4 +20,4 @@ %br/ = link_to "Turn off these notifications", edit_member_registration_url -= render :partial => 'signature' \ No newline at end of file += render :partial => 'signature', :locals => { :site_name => site_name } \ No newline at end of file diff --git a/app/views/notifier/planting_reminder.html.haml b/app/views/notifier/planting_reminder.html.haml index 4dea05123..09cea8e15 100644 --- a/app/views/notifier/planting_reminder.html.haml +++ b/app/views/notifier/planting_reminder.html.haml @@ -59,7 +59,7 @@ %h2 See you soon on #{site_name}! -= render :partial => 'signature' += render :partial => 'signature', :locals => { :site_name => site_name } %hr/ %p From 0fc4c3cb4d8b8e43394b907b78ae73ccdaa0c372 Mon Sep 17 00:00:00 2001 From: Skud Date: Tue, 10 Feb 2015 18:48:06 +1100 Subject: [PATCH 62/67] Made search result page show a suitable title --- app/controllers/crops_controller.rb | 7 ++++--- app/views/crops/search.html.haml | 5 ++++- app/views/layouts/_header.html.haml | 4 +++- db/schema.rb | 1 + spec/features/crops/crop_search_spec.rb | 17 +++++++++++++++++ 5 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 spec/features/crops/crop_search_spec.rb diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index 19f55d7ef..42c004b80 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -60,8 +60,9 @@ class CropsController < ApplicationController # GET /crops/search def search - @all_matches = Crop.search(params[:search]) - exact_match = Crop.find_by_name(params[:search]) + @search = params[:search] + @all_matches = Crop.search(@search) + exact_match = Crop.find_by_name(@search) if exact_match @all_matches.delete(exact_match) @all_matches.unshift(exact_match) @@ -69,7 +70,7 @@ class CropsController < ApplicationController respond_to do |format| format.html - format.json { render :json => Crop.search(params[:term]) } + format.json { render :json => Crop.search(@search) } end end diff --git a/app/views/crops/search.html.haml b/app/views/crops/search.html.haml index 2ed095402..455fb497d 100644 --- a/app/views/crops/search.html.haml +++ b/app/views/crops/search.html.haml @@ -1,4 +1,7 @@ -- content_for :title, "Crops matching #{@search}" +- if @search + - content_for :title, "Crops matching \"#{@search}\"" +- else + - content_for :title, "Crop search" - if @all_matches.empty? %h2 No results found diff --git a/app/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml index 691de3681..f9fe795a8 100644 --- a/app/views/layouts/_header.html.haml +++ b/app/views/layouts/_header.html.haml @@ -68,9 +68,11 @@ %li= link_to 'Sign in', new_member_session_path %li= link_to 'Sign up', new_member_registration_path - = form_tag crops_search_path, :method => :get, :class => 'navbar-form pull-right' do + = form_tag crops_search_path, :method => :get, :id => 'navbar-search', :class => 'navbar-form pull-right' do .input + = label_tag :search, "Search crop database:", :class => 'sr-only' = text_field_tag 'search', nil, :class => 'search-query input-medium form-control', :placeholder => 'Search crops' + = submit_tag "Search", :class => 'btn sr-only' - # anchor tag for accessibility link to skip the navigation menu %a{:name => 'skipnav'} diff --git a/db/schema.rb b/db/schema.rb index ebafd6fa2..4d3f407b9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -285,6 +285,7 @@ ActiveRecord::Schema.define(version: 20150201064502) do t.datetime "updated_at" t.string "slug" t.integer "forum_id" + t.integer "parent_id" end add_index "posts", ["created_at", "author_id"], name: "index_posts_on_created_at_and_author_id", using: :btree diff --git a/spec/features/crops/crop_search_spec.rb b/spec/features/crops/crop_search_spec.rb new file mode 100644 index 000000000..e28673cb3 --- /dev/null +++ b/spec/features/crops/crop_search_spec.rb @@ -0,0 +1,17 @@ +require 'rails_helper' + +feature "crop search" do + scenario "search results show the search term in title" do + visit root_path + within "form#navbar-search" do + fill_in "search", with: "tomato" + click_button "Search" + end + expect(page).to have_css "h1", text: "Crops matching \"tomato\"" + end + + scenario "search page with no search term shows suitable title" do + visit crops_search_path + expect(page).to have_css "h1", text: "Crop search" + end +end From 9ccef5471f586846277fe83b1ae04d48d8bb2084 Mon Sep 17 00:00:00 2001 From: Skud Date: Tue, 10 Feb 2015 19:18:57 +1100 Subject: [PATCH 63/67] Added search form to crop search result page --- app/views/crops/search.html.haml | 7 +++++++ spec/features/crops/crop_search_spec.rb | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/app/views/crops/search.html.haml b/app/views/crops/search.html.haml index 455fb497d..05fbcfe09 100644 --- a/app/views/crops/search.html.haml +++ b/app/views/crops/search.html.haml @@ -3,6 +3,13 @@ - else - content_for :title, "Crop search" +%div + = form_tag crops_search_path, :method => :get, :id => 'crop-search', :class => 'form-inline' do + .form-group + = label_tag :search, "Search crops:", :class => 'sr-only' + = text_field_tag 'search', nil, :class => 'search-query input-medium form-control', :placeholder => 'Search crops', :value => @search + = submit_tag "Search", :class => 'btn btn-primary' + - if @all_matches.empty? %h2 No results found %p diff --git a/spec/features/crops/crop_search_spec.rb b/spec/features/crops/crop_search_spec.rb index e28673cb3..48e68dfc2 100644 --- a/spec/features/crops/crop_search_spec.rb +++ b/spec/features/crops/crop_search_spec.rb @@ -14,4 +14,9 @@ feature "crop search" do visit crops_search_path expect(page).to have_css "h1", text: "Crop search" end + + scenario "search page has a search form on it" do + visit crops_search_path + expect(page).to have_css "form#crop-search" + end end From 78c4fc36b138b45c8f11723c7eaf7da0f8242063 Mon Sep 17 00:00:00 2001 From: Skud Date: Tue, 10 Feb 2015 19:26:07 +1100 Subject: [PATCH 64/67] Paginate search results ... and include total number in subtitle --- app/controllers/crops_controller.rb | 1 + app/views/crops/search.html.haml | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index 42c004b80..8dee17722 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -62,6 +62,7 @@ class CropsController < ApplicationController def search @search = params[:search] @all_matches = Crop.search(@search) + @paginated_matches = @all_matches.paginate(:page => params[:page]) exact_match = Crop.find_by_name(@search) if exact_match @all_matches.delete(exact_match) diff --git a/app/views/crops/search.html.haml b/app/views/crops/search.html.haml index 05fbcfe09..9b57e1b7a 100644 --- a/app/views/crops/search.html.haml +++ b/app/views/crops/search.html.haml @@ -1,5 +1,7 @@ - if @search - content_for :title, "Crops matching \"#{@search}\"" + - if @all_matches + - content_for :subtitle, "#{@all_matches.size} total" - else - content_for :title, "Crop search" @@ -19,10 +21,15 @@ = link_to "browsing our crop database", crops_path instead. -- else - %div#all_matches +- else + %div.pagination + = will_paginate @paginated_matches + + %div#paginated_matches .row - - @all_matches.each do |c| + - @paginated_matches.each do |c| .col-md-2.six-across = render :partial => "thumbnail", :locals => { :crop => c } + %div.pagination + = will_paginate @paginated_matches From 623dbdd418d573adcaad1873cd29b409477be58e Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Tue, 10 Feb 2015 19:58:43 +1100 Subject: [PATCH 65/67] fix search deleting crops --- app/models/crop.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/crop.rb b/app/models/crop.rb index f11d78567..1f514f3ce 100644 --- a/app/models/crop.rb +++ b/app/models/crop.rb @@ -315,7 +315,7 @@ class Crop < ActiveRecord::Base ) return response.records.to_a else - where("name ILIKE ?", "%#{query}%") + where("name ILIKE ?", "%#{query}%").load end end From 2ab73d3df660d99c836783e0017579ecc752e624 Mon Sep 17 00:00:00 2001 From: Taylor Griffin Date: Tue, 10 Feb 2015 19:59:42 +1100 Subject: [PATCH 66/67] call site name from inside signature partial --- app/views/notifier/_signature.html.haml | 2 ++ app/views/notifier/crop_request_approved.html.haml | 2 +- app/views/notifier/crop_request_rejected.html.haml | 2 +- app/views/notifier/new_crop_request.html.haml | 2 +- app/views/notifier/notify.html.haml | 2 +- app/views/notifier/planting_reminder.html.haml | 2 +- 6 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/views/notifier/_signature.html.haml b/app/views/notifier/_signature.html.haml index 30101610d..14a7d47a7 100644 --- a/app/views/notifier/_signature.html.haml +++ b/app/views/notifier/_signature.html.haml @@ -1,3 +1,5 @@ +- site_name = ENV['GROWSTUFF_SITE_NAME'] + %p The #{site_name} team. %br/ diff --git a/app/views/notifier/crop_request_approved.html.haml b/app/views/notifier/crop_request_approved.html.haml index 95a1da688..5fea20246 100644 --- a/app/views/notifier/crop_request_approved.html.haml +++ b/app/views/notifier/crop_request_approved.html.haml @@ -12,5 +12,5 @@ %li = link_to "Stash seeds for #{@crop.name}", new_seed_url(crop_id: @crop.id) -= render :partial => 'signature', :locals => { :site_name => site_name } += render :partial => 'signature' diff --git a/app/views/notifier/crop_request_rejected.html.haml b/app/views/notifier/crop_request_rejected.html.haml index 578eb5bc5..c58e2546b 100644 --- a/app/views/notifier/crop_request_rejected.html.haml +++ b/app/views/notifier/crop_request_rejected.html.haml @@ -6,4 +6,4 @@ = @crop.reason_for_rejection -= render :partial => 'signature', :locals => { :site_name => site_name } \ No newline at end of file += render :partial => 'signature' \ No newline at end of file diff --git a/app/views/notifier/new_crop_request.html.haml b/app/views/notifier/new_crop_request.html.haml index 395ad2741..163c898f4 100644 --- a/app/views/notifier/new_crop_request.html.haml +++ b/app/views/notifier/new_crop_request.html.haml @@ -18,4 +18,4 @@ %p Thanks for your help! -= render :partial => 'signature', :locals => { :site_name => site_name } \ No newline at end of file += render :partial => 'signature' \ No newline at end of file diff --git a/app/views/notifier/notify.html.haml b/app/views/notifier/notify.html.haml index 7260d84be..ed9cf32f2 100644 --- a/app/views/notifier/notify.html.haml +++ b/app/views/notifier/notify.html.haml @@ -20,4 +20,4 @@ %br/ = link_to "Turn off these notifications", edit_member_registration_url -= render :partial => 'signature', :locals => { :site_name => site_name } \ No newline at end of file += render :partial => 'signature' \ No newline at end of file diff --git a/app/views/notifier/planting_reminder.html.haml b/app/views/notifier/planting_reminder.html.haml index 09cea8e15..4dea05123 100644 --- a/app/views/notifier/planting_reminder.html.haml +++ b/app/views/notifier/planting_reminder.html.haml @@ -59,7 +59,7 @@ %h2 See you soon on #{site_name}! -= render :partial => 'signature', :locals => { :site_name => site_name } += render :partial => 'signature' %hr/ %p From 66fcad69fa0c9a6d9c50321d99d18c23ead9b3d0 Mon Sep 17 00:00:00 2001 From: Skud Date: Tue, 10 Feb 2015 20:48:36 +1100 Subject: [PATCH 67/67] Paginate search results, make sexy subtitles --- app/controllers/crops_controller.rb | 6 ++- app/views/crops/index.html.haml | 11 +++--- spec/features/crops/browse_crops_spec.rb | 19 +++++++++ spec/views/crops/index.html.haml_spec.rb | 19 ++------- spec/views/crops/search.html.haml_spec.rb | 48 ----------------------- 5 files changed, 31 insertions(+), 72 deletions(-) create mode 100644 spec/features/crops/browse_crops_spec.rb delete mode 100644 spec/views/crops/search.html.haml_spec.rb diff --git a/app/controllers/crops_controller.rb b/app/controllers/crops_controller.rb index 8dee17722..160403c24 100644 --- a/app/controllers/crops_controller.rb +++ b/app/controllers/crops_controller.rb @@ -9,10 +9,12 @@ class CropsController < ApplicationController @sort = params[:sort] if @sort == 'alpha' # alphabetical order - @crops = Crop.includes(:scientific_names, {:plantings => :photos}).paginate(:page => params[:page]) + @crops = Crop.includes(:scientific_names, {:plantings => :photos}) + @paginated_crops = @crops.paginate(:page => params[:page]) else # default to sorting by popularity - @crops = Crop.popular.includes(:scientific_names, {:plantings => :photos}).paginate(:page => params[:page]) + @crops = Crop.popular.includes(:scientific_names, {:plantings => :photos}) + @paginated_crops = @crops.paginate(:page => params[:page]) end respond_to do |format| diff --git a/app/views/crops/index.html.haml b/app/views/crops/index.html.haml index 38ce986e0..d1be6fa49 100644 --- a/app/views/crops/index.html.haml +++ b/app/views/crops/index.html.haml @@ -1,4 +1,5 @@ -- content_for :title, "Crops" +- content_for :title, "Browse crops" +- content_for :subtitle, "#{@crops.size} total" - if can? :wrangle, Crop = link_to 'Wrangle Crops', wrangle_crops_path, :class => 'btn btn-primary' @@ -14,11 +15,10 @@ = submit_tag "Show", :class => 'btn btn-primary' %div.pagination - = page_entries_info @crops, :model => "crops" - = will_paginate @crops + = will_paginate @paginated_crops .row - - @crops.each do |crop| + - @paginated_crops.each do |crop| .col-md-2.six-across = render :partial => "thumbnail", :locals => { :crop => crop } @@ -27,8 +27,7 @@ = link_to 'New Crop', new_crop_path, {:class => 'btn btn-primary'} %div.pagination - = page_entries_info @crops, :model => "crops" - = will_paginate @crops + = will_paginate @paginated_crops %ul.list-inline diff --git a/spec/features/crops/browse_crops_spec.rb b/spec/features/crops/browse_crops_spec.rb new file mode 100644 index 000000000..5df5dbd36 --- /dev/null +++ b/spec/features/crops/browse_crops_spec.rb @@ -0,0 +1,19 @@ +require 'rails_helper' + +feature "browse crops" do + + let(:tomato) { FactoryGirl.create(:tomato) } + let(:maize) { FactoryGirl.create(:maize) } + + scenario "has a form for sorting by" do + visit crops_path + expect(page).to have_css "select#sort" + end + + scenario "shows a list of crops" do + crop1 = tomato + visit crops_path + expect(page).to have_content crop1.name + end + +end diff --git a/spec/views/crops/index.html.haml_spec.rb b/spec/views/crops/index.html.haml_spec.rb index 69792ba76..33ab3e07e 100644 --- a/spec/views/crops/index.html.haml_spec.rb +++ b/spec/views/crops/index.html.haml_spec.rb @@ -8,24 +8,11 @@ describe "crops/index" do total_entries = 2 @tomato = FactoryGirl.create(:tomato) @maize = FactoryGirl.create(:maize) - crops = WillPaginate::Collection.create(page, per_page, total_entries) do |pager| + assign(:crops, [@tomato, @maize]) + paginated_crops = WillPaginate::Collection.create(page, per_page, total_entries) do |pager| pager.replace([ @tomato, @maize ]) end - assign(:crops, crops) - end - - it "has a form for sorting by" do - render - assert_select "form" - assert_select "select#sort" - assert_select "option[value=alpha]" - assert_select "option[value=popular]" - end - - it "renders a list of crops" do - render - assert_select "a", :text => @maize.name - assert_select "a", :text => @tomato.name + assign(:paginated_crops, paginated_crops) end it "shows photos where available" do diff --git a/spec/views/crops/search.html.haml_spec.rb b/spec/views/crops/search.html.haml_spec.rb deleted file mode 100644 index 8458f254e..000000000 --- a/spec/views/crops/search.html.haml_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -require 'rails_helper' - -describe "crops/search" do - before(:each) do - controller.stub(:current_user) { nil } - end - - context "has results" do - - before :each do - @tomato = FactoryGirl.create(:tomato) - @roma = FactoryGirl.create(:crop, :name => 'Roma tomato', :parent => @tomato) - assign(:search, 'tomato') - assign(:all_matches, [@tomato, @roma]) - render - end - - it "shows exact matches" do - assert_select "div#all_matches" do - assert_select "a[href=#{crop_path(@tomato)}]" - end - end - - it "shows partial matches" do - assert_select "div#all_matches" do - assert_select "a[href=#{crop_path(@roma)}]" - end - end - end - - context "no results" do - before :each do - assign(:all_matches, []) - assign(:search, 'tomato') - render - end - - it "tells you there are no matches" do - rendered.should have_content "No results found" - end - - it "links to browse crops" do - assert_select "a", :href => crops_path - rendered.should have_content "Try browsing our crop database instead" - end - end - -end