diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index 26348c670..c96b99f3a 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -1,5 +1,27 @@ class HomeController < ApplicationController skip_authorize_resource + def index + @member_count = Member.confirmed.count + @crop_count = Crop.count + @planting_count = Planting.count + @garden_count = Garden.count + + @interesting_members = Member.interesting.limit(6) + + # customise what we show on the homepage based on whether you're + # logged in or not. + @member = current_member + @plantings = current_member ? + current_member.plantings.limit(10) : + Planting.limit(10) + @posts = current_member ? + current_member.posts.limit(10) : + Post.limit(10) + + respond_to do |format| + format.html # index.html.haml + end end + end diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb index 870510420..4d6d60f8b 100644 --- a/app/controllers/members_controller.rb +++ b/app/controllers/members_controller.rb @@ -9,7 +9,7 @@ class MembersController < ApplicationController end def show - @member = Member.find_confirmed(params[:id]) + @member = Member.confirmed.find(params[:id]) @posts = @member.posts # The garden form partial is called from the "New Garden" tab; # it requires a garden to be passed in @garden. diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb index 0c37bf28c..7b49c326f 100644 --- a/app/controllers/notifications_controller.rb +++ b/app/controllers/notifications_controller.rb @@ -1,18 +1,15 @@ class NotificationsController < ApplicationController load_and_authorize_resource # GET /notifications - # GET /notifications.json def index @notifications = Notification.find_all_by_recipient_id(current_member) respond_to do |format| format.html # index.html.erb - format.json { render json: @notifications } end end # GET /notifications/1 - # GET /notifications/1.json def show @notification = Notification.find(params[:id]) @notification.read = true @@ -20,19 +17,42 @@ class NotificationsController < ApplicationController respond_to do |format| format.html # show.html.erb - format.json { render json: @notification } + end + end + + # GET /notifications/new + + def new + @notification = Notification.new + @recipient = Member.find_by_id(params[:recipient_id]) + + respond_to do |format| + format.html # new.html.erb end end # DELETE /notifications/1 - # DELETE /notifications/1.json def destroy @notification = Notification.find(params[:id]) @notification.destroy respond_to do |format| format.html { redirect_to notifications_url } - format.json { head :no_content } + end + end + + # POST /notifications + def create + params[:notification][:sender_id] = current_member.id + @notification = Notification.new(params[:notification]) + @recipient = Member.find_by_id(params[:notification][:recipient_id]) + + respond_to do |format| + if @notification.save + format.html { redirect_to @recipient, notice: 'Message was successfully sent.' } + else + format.html { render action: "new" } + end end end end diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index e725be734..1ca2b5f94 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -18,6 +18,7 @@ class PostsController < ApplicationController # GET /posts/1.json def show @post = Post.find(params[:id]) + @comments = @post.comments respond_to do |format| format.html # show.html.haml diff --git a/app/models/ability.rb b/app/models/ability.rb index 38385a46f..6d7fb6ba2 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -7,6 +7,7 @@ class Ability # everyone can do these things, even non-logged in can :read, :all cannot :read, Notification + cannot :create, Notification # nobody should be able to view this except admins cannot :read, Role @@ -28,7 +29,13 @@ class Ability # can read/delete notifications that were sent to them can :read, Notification, :recipient_id => member.id can :destroy, Notification, :recipient_id => member.id - # note we don't support create/update for notifications + # can send a private message to anyone but themselves + # note: sadly, we can't test for this from the view, but it works + # for the model/controller + can :create, Notification do |n| + n.recipient_id != member.id + end + # note we don't support update for notifications # only crop wranglers can create/edit/destroy crops if member.has_role? :crop_wrangler diff --git a/app/models/comment.rb b/app/models/comment.rb index 395d99277..ea2082bf9 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -3,6 +3,8 @@ class Comment < ActiveRecord::Base belongs_to :author, :class_name => 'Member' belongs_to :post + default_scope order("created_at asc") + after_create do recipient = self.post.author.id sender = self.author.id diff --git a/app/models/member.rb b/app/models/member.rb index 11f6176a3..18396862a 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -10,7 +10,15 @@ class Member < ActiveRecord::Base has_and_belongs_to_many :roles has_many :notifications, :foreign_key => 'recipient_id' has_many :sent_notifications, :foreign_key => 'sender_id' + default_scope order("lower(login_name) asc") + scope :confirmed, where('confirmed_at IS NOT NULL') + scope :located, where('location IS NOT NULL') + scope :recently_signed_in, reorder('updated_at DESC') + + # this is used on the signed-out homepage so we're basically + # just trying to select some members who look good. + scope :interesting, confirmed.located.recently_signed_in # Include default devise modules. Others available are: # :token_authenticatable, :confirmable, @@ -68,14 +76,6 @@ class Member < ActiveRecord::Base end end - def self.find_confirmed(params) - find(params, :conditions => 'confirmed_at IS NOT NULL') - end - - def self.confirmed - where('confirmed_at IS NOT NULL') - end - def to_s return login_name end diff --git a/app/models/notification.rb b/app/models/notification.rb index 1b53e36dc..1be9da637 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -1,5 +1,5 @@ class Notification < ActiveRecord::Base - attr_accessible :sender_id, :recipient_id, + attr_accessible :sender_id, :recipient_id, :subject, :body, :post_id, :read belongs_to :sender, :class_name => 'Member' diff --git a/app/models/planting.rb b/app/models/planting.rb index 311d711cf..d5c477957 100644 --- a/app/models/planting.rb +++ b/app/models/planting.rb @@ -2,17 +2,29 @@ class Planting < ActiveRecord::Base extend FriendlyId friendly_id :planting_slug, use: :slugged - attr_accessible :crop_id, :description, :garden_id, :planted_at, :quantity, - :planted_at_string + attr_accessible :crop_id, :description, :garden_id, :planted_at, + :quantity, :sunniness, :planted_at_string belongs_to :garden belongs_to :crop - delegate :default_scientific_name, + default_scope order("created_at desc") + + delegate :system_name, + :en_wikipedia_url, + :default_scientific_name, :plantings_count, :to => :crop, :prefix => true + default_scope order("created_at desc") + + SUNNINESS_VALUES = %w(sun semi-shade shade) + validates :sunniness, :inclusion => { :in => SUNNINESS_VALUES, + :message => "%{value} is not a valid sunniness value" }, + :allow_nil => true, + :allow_blank => true + def planting_slug "#{owner.login_name}-#{garden}-#{crop}".downcase.gsub(' ', '-') end @@ -34,6 +46,6 @@ class Planting < ActiveRecord::Base end def planted_at_string=(str) - self.planted_at = Time.parse(str) + self.planted_at = str == '' ? nil : Time.parse(str) end end diff --git a/app/views/crops/_thumbnail.html.haml b/app/views/crops/_thumbnail.html.haml index b68a01526..a6c453a1e 100644 --- a/app/views/crops/_thumbnail.html.haml +++ b/app/views/crops/_thumbnail.html.haml @@ -1,5 +1,4 @@ - -.thumbnail(style='height: 200px') +.thumbnail(style='height: 220px') - if crop = link_to image_tag('http://placehold.it/150x150', :alt => '', :class => 'img-rounded'), crop %p diff --git a/app/views/home/_blurb.html.haml b/app/views/home/_blurb.html.haml index 9a07fe558..f5f4b4676 100644 --- a/app/views/home/_blurb.html.haml +++ b/app/views/home/_blurb.html.haml @@ -1,6 +1,15 @@ -%h1 - = Growstuff::Application.config.site_name +%h1= Growstuff::Application.config.site_name -%p #{Growstuff::Application.config.site_name} is a community of food gardeners working together to build an open source platform to track, share, and discuss edible gardens and sustainable lifestyles. You can join us right now and be part of growing our website, from seed to harvest. We welcome you regardless of your experience, and invite you to be part of our development process. +%p + #{Growstuff::Application.config.site_name} is a community of food gardeners. We're building an open source platform to track, share, and discuss edible gardens and sustainable lifestyles. We offer growing information tailored to your location, and help you connect with your local food-growing community. -%p= link_to 'Learn more', 'http://wiki.growstuff.org/', :class => 'btn btn-primary btn-large' + %strong + So far, + = link_to "#{@member_count} members", members_path + have planted + = link_to "#{@crop_count} crops", crops_path + #{@planting_count} times in #{@garden_count} gardens. + + You could be one of them. Sign up for a free account and start tracking your food garden today. +%p + = link_to 'Join now', new_member_registration_path, :class => 'btn btn-primary btn-large' diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml index 572567c2c..866644c5a 100644 --- a/app/views/home/index.html.haml +++ b/app/views/home/index.html.haml @@ -45,78 +45,30 @@ .row .span6 %h2 Your recent plantings - - if current_member.plantings.count > 0 - %ul - - current_member.plantings.limit(10).each do |p| - %li - = link_to "#{p.crop.system_name} in #{p.location}", p - - if p.planted_at - on - = p.planted_at.to_s(:date) - - else - %p None yet. - - if can? :create, Planting - %p= link_to "Plant something", new_planting_path, :class => 'btn btn-primary' + = render :partial => 'shared/recent_plantings' .span6 %h2 Your recent posts - - if current_member.posts.count > 0 - %ul - - current_member.posts.limit(10).each do |p| - %li - = link_to p.subject, p - - if p.forum - in - = link_to p.forum.name, p.forum - on - = p.created_at.to_s(:date) - - else - %p None yet. - - if can? :create, Planting - %p= link_to "Post something", new_post_path, :class => 'btn btn-primary' - - .span6 - + = render :partial => 'shared/recent_posts' - else .visible-desktop.visible-tablet .hero-unit = render :partial => 'blurb' - .visible-phone = render :partial => 'blurb' - .row - .span3 - %h2 Track - %p - Track your garden, your - = link_to 'crops', crops_path - , and everything to do with them. | - Remember what you planted or harvested, and plan for what you want to do next. | - Import and export your data to a spreadsheet or other format. + - if @interesting_members + %h2 Some of our members + %ul.thumbnails + - @interesting_members.each do |m| + %li.span2 + = render :partial => "members/thumbnail", :locals => { :member => m } - .span3 - %h2 Connect - %p - Connect with friends, people who live in your area, or others | - who share your gardening interests. Show off your crops and | - harvests, share updates and tips, and - = link_to 'see', posts_path - what everyone else is doing, too. - .span3 - %h2 Learn - %p - Browse our - = link_to 'crops', crops_path - database and learn about food plants for your - climate and garden type. Read other - = link_to "members' posts", posts_path - and tips, or post questions and discuss food gardening issues in our forums. - .span3 - %h2 Trade - %p - Use #{ Growstuff::Application.config.site_name } as a marketplace - for everything related to food gardens. Buy and sell, trade, - or give away anything from seeds to garden supplies, or find - events and businesses in your area. + .row + .span6 + %h2 Recent plantings + = render :partial => 'shared/recent_plantings' + .span6 + %h2 Recent posts + = render :partial => 'shared/recent_posts' diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index d8a8088e4..cc67cedee 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -25,4 +25,4 @@ / Placed at the end of the document so the pages load faster = javascript_include_tag "application" - = Growstuff::Application.config.analytics_code + != Growstuff::Application.config.analytics_code diff --git a/app/views/members/_thumbnail.html.haml b/app/views/members/_thumbnail.html.haml new file mode 100644 index 000000000..8ccd68681 --- /dev/null +++ b/app/views/members/_thumbnail.html.haml @@ -0,0 +1,8 @@ +.thumbnail(style="height: 220px") + = render :partial => "members/avatar", :locals => { :member => member } + %p + = link_to member.to_s, member + - if member.location + %br/ + %i + %small= member.location diff --git a/app/views/members/index.html.haml b/app/views/members/index.html.haml index bdf23882d..9ae6c3744 100644 --- a/app/views/members/index.html.haml +++ b/app/views/members/index.html.haml @@ -11,9 +11,7 @@ %ul.thumbnails - @members.each do |m| %li.span2 - .thumbnail(style="height: 190px") - = render :partial => "members/avatar", :locals => { :member => m } - = link_to m.to_s, m + = render :partial => "members/thumbnail", :locals => { :member => m } %div.pagination = page_entries_info @members, :model => "members" diff --git a/app/views/members/show.html.haml b/app/views/members/show.html.haml index 881d2010d..095b3ad1f 100644 --- a/app/views/members/show.html.haml +++ b/app/views/members/show.html.haml @@ -6,6 +6,11 @@ .span3 = render :partial => "members/avatar", :locals => { :member => @member } + -if can? :create, Notification and current_member != @member + %p + %br/ + =link_to 'Send Message', new_notification_path(:sender_id => current_member.id, :recipient_id => @member.id), :class => 'btn btn-primary' + %p = "Member since: #{@member.created_at.to_s(:date)}" - if @member.location.to_s != '' diff --git a/app/views/notifications/_form.html.haml b/app/views/notifications/_form.html.haml new file mode 100644 index 000000000..a0b9f6d55 --- /dev/null +++ b/app/views/notifications/_form.html.haml @@ -0,0 +1,22 @@ += form_for @notification do |f| + - if @notification.errors.any? + #error_explanation + %h2= "#{pluralize(@post.errors.count, "error")} prohibited this message from being sent:" + %ul + - @notification.errors.full_messages.each do |msg| + %li= msg + + .field + = f.hidden_field :recipient_id, :value => @recipient.id + + %p + To: + = link_to @recipient, @recipient + = label_tag :notification, "Subject:" + = f.text_field :subject, :class => 'input-block-level' + = label_tag :body, "Type your message here:" + = f.text_area :body, :rows => 12, :class => 'input-block-level' + %span.help-block + = render :partial => "shared/markdown_help" + + = f.submit "Send", :class => 'btn btn-primary' diff --git a/app/views/notifications/index.html.haml b/app/views/notifications/index.html.haml index 3352120cd..44b408ce0 100644 --- a/app/views/notifications/index.html.haml +++ b/app/views/notifications/index.html.haml @@ -23,9 +23,9 @@ %strong= link_to n.subject, notification_path(n) %td - if n.read - = n.created_at.to_s(:date) + = n.created_at - else - %strong= n.created_at.to_s(:date) + %strong= n.created_at %td = link_to 'Delete', n, method: :delete, data: { confirm: 'Are you sure?' }, :class => 'btn btn-mini' - else diff --git a/app/views/notifications/new.html.haml b/app/views/notifications/new.html.haml new file mode 100644 index 000000000..f34343133 --- /dev/null +++ b/app/views/notifications/new.html.haml @@ -0,0 +1,4 @@ += content_for :title, "Send a message to #{@recipient}" + +=render 'form' + diff --git a/app/views/notifications/show.html.haml b/app/views/notifications/show.html.haml index f9a1870ed..cbd66aeaf 100644 --- a/app/views/notifications/show.html.haml +++ b/app/views/notifications/show.html.haml @@ -4,7 +4,7 @@ From = link_to @notification.sender, @notification.sender on - = @notification.created_at.to_s(:date) + = @notification.created_at - if @notification.post_id in response to: diff --git a/app/views/notifier/notify.html.haml b/app/views/notifier/notify.html.haml index 7623d2be8..cbbb82bcd 100644 --- a/app/views/notifier/notify.html.haml +++ b/app/views/notifier/notify.html.haml @@ -3,18 +3,18 @@ %p You have received a message from - = link_to @notification.sender.login_name, url_for(:controller => 'members', :action => 'show', :id => @notification.sender.id, :only_path => false ) - on #{site_name} at #{@notification.created_at.to_s(:date)} + = link_to @notification.sender.login_name, member_url(@notification.sender) + on #{site_name} at #{@notification.created_at} - if @notification.post in response to - = link_to @notification.post.subject, url_for(:controller => 'posts', :action => 'show', :id => @notification.post.id, :only_path => false) + = link_to @notification.post.subject, post_url(@notification.post) \. %blockquote :markdown #{strip_tags @notification.body} %p - = link_to "View this message in your inbox", url_for(:controller => 'notifications', :action => 'show', :id => @notification.id, :only_path => false) + = link_to "View this message in your inbox", notification_url(@notification) %br/ = link_to "Turn off these notifications", edit_member_registration_url diff --git a/app/views/plantings/_form.html.haml b/app/views/plantings/_form.html.haml index 092ca9de0..2a8906add 100644 --- a/app/views/plantings/_form.html.haml +++ b/app/views/plantings/_form.html.haml @@ -20,6 +20,10 @@ = f.label 'How many?', :class => 'control-label' .controls = f.number_field :quantity, :class => 'input-small' + .control-group + = f.label 'Sun or shade?', :class => 'control-label' + .controls + = f.select(:sunniness, Planting::SUNNINESS_VALUES, {:include_blank => true}) .control-group = f.label 'Tell us more about it', :class => 'control-label' .controls= f.text_area :description, :rows => 6 diff --git a/app/views/plantings/_thumbnail.html.haml b/app/views/plantings/_thumbnail.html.haml index e5338ccd8..2e6147f02 100644 --- a/app/views/plantings/_thumbnail.html.haml +++ b/app/views/plantings/_thumbnail.html.haml @@ -8,7 +8,7 @@ %p Planted - if planting.planted_at - = planting.planted_at.to_s(:date) + = planting.planted_at in = link_to planting.location, planting.garden diff --git a/app/views/plantings/show.html.haml b/app/views/plantings/show.html.haml index 77b59f59f..f8e375166 100644 --- a/app/views/plantings/show.html.haml +++ b/app/views/plantings/show.html.haml @@ -4,7 +4,7 @@ .span6 %p %b Planted: - = @planting.planted_at ? @planting.planted_at.to_s(:date) : "not specified" + = @planting.planted_at ? @planting.planted_at : "not specified" %p %b Where: =link_to "#{@planting.owner}'s", @planting.owner @@ -15,6 +15,12 @@ %b Quantity: = @planting.quantity != 0 ? @planting.quantity : "not specified" + - if ! @planting.sunniness.blank? + %p + %b Sun or shade? + = @planting.sunniness + + - if can? :edit, @planting or can? :destroy, @planting %p - if can? :edit, @planting diff --git a/app/views/posts/show.html.haml b/app/views/posts/show.html.haml index c54fd1e1a..532b93b15 100644 --- a/app/views/posts/show.html.haml +++ b/app/views/posts/show.html.haml @@ -12,10 +12,10 @@ %a{:name => "comments"} -- if @post.comments.length > 0 +- if @comments %h2 - =pluralize(@post.comments.length, "comment") - - @post.comments.each do |c| + =pluralize(@comments.length, "comment") + - @comments.each do |c| = render :partial => "comments/single", :locals => { :comment => c } - else diff --git a/app/views/shared/_recent_plantings.html.haml b/app/views/shared/_recent_plantings.html.haml new file mode 100644 index 000000000..4fda76254 --- /dev/null +++ b/app/views/shared/_recent_plantings.html.haml @@ -0,0 +1,12 @@ +- if @plantings + %ul + - @plantings.each do |p| + %li + = link_to "#{p.crop_system_name} in #{p.location}", p + - if p.planted_at + on + = p.planted_at +- else + %p None yet. +- if can? :create, Planting + %p= link_to "Plant something", new_planting_path, :class => 'btn btn-primary' diff --git a/app/views/shared/_recent_posts.html.haml b/app/views/shared/_recent_posts.html.haml new file mode 100644 index 000000000..82d06a2d7 --- /dev/null +++ b/app/views/shared/_recent_posts.html.haml @@ -0,0 +1,17 @@ +- if @posts + %ul + - @posts.each do |p| + %li + = link_to p.subject, p + - unless @member + posted by + = link_to p.author, p.author + - if p.forum + in + = link_to p.forum.name, p.forum + on + = p.created_at.to_s(:date) +- else + %p None yet. +- if can? :create, Post + %p= link_to "Post something", new_post_path, :class => 'btn btn-primary' diff --git a/config/initializers/time_formats.rb b/config/initializers/time_formats.rb index 63c12499e..0b26541d9 100644 --- a/config/initializers/time_formats.rb +++ b/config/initializers/time_formats.rb @@ -1 +1,7 @@ +Time::DATE_FORMATS[:default] = '%B %d, %Y at %H:%M' +Date::DATE_FORMATS[:default] = "%B %d, %Y" + Time::DATE_FORMATS[:date] = "%B %d, %Y" +Date::DATE_FORMATS[:date] = "%B %d, %Y" + +Time::DATE_FORMATS[:datetime] = '%B %d, %Y at %H:%M' diff --git a/db/migrate/20130329045744_add_sunniness_to_planting.rb b/db/migrate/20130329045744_add_sunniness_to_planting.rb new file mode 100644 index 000000000..8fae8d1d0 --- /dev/null +++ b/db/migrate/20130329045744_add_sunniness_to_planting.rb @@ -0,0 +1,5 @@ +class AddSunninessToPlanting < ActiveRecord::Migration + def change + add_column :plantings, :sunniness, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 6c5e563d8..f13ce0fd1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130327120024) do +ActiveRecord::Schema.define(:version => 20130329045744) do create_table "comments", :force => true do |t| t.integer "post_id", :null => false @@ -116,6 +116,7 @@ ActiveRecord::Schema.define(:version => 20130327120024) do t.datetime "created_at", :null => false t.datetime "updated_at", :null => false t.string "slug" + t.string "sunniness" end add_index "plantings", ["slug"], :name => "index_plantings_on_slug", :unique => true diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb new file mode 100644 index 000000000..839545b51 --- /dev/null +++ b/spec/controllers/home_controller_spec.rb @@ -0,0 +1,39 @@ +require 'spec_helper' + +describe HomeController do + + describe "GET index" do + it "assigns counts" do + @planting = FactoryGirl.create(:planting) + get :index, {} + assigns(:garden_count).should == 2 # auto-created for member and planting + assigns(:planting_count).should == 1 + assigns(:crop_count).should == 1 + assigns(:member_count).should == 1 + end + + it "assigns posts and plantings" do + @post = FactoryGirl.create(:post) + @planting = FactoryGirl.create(:planting) + get :index, {} + assigns(:posts).should eq [@post] + assigns(:plantings).should eq [@planting] + end + + it 'assigns interesting members' do + @member = FactoryGirl.create(:geolocated_member) + get :index, {} + assigns(:interesting_members).should eq [@member] + end + + context 'logged in' do + + login_member + + it 'assigns member' do + get :index, {} + assigns(:member).should be_an_instance_of Member + end + end + end +end diff --git a/spec/controllers/notifications_controller_spec.rb b/spec/controllers/notifications_controller_spec.rb index ded781e01..155273f07 100644 --- a/spec/controllers/notifications_controller_spec.rb +++ b/spec/controllers/notifications_controller_spec.rb @@ -5,7 +5,22 @@ describe NotificationsController do login_member def valid_attributes - { "recipient_id" => subject.current_member.id } + { + "recipient_id" => subject.current_member.id, + "sender_id" => FactoryGirl.create(:member).id + } + end + + # this gets a bit confused because for most of the notification tests + # (reading, etc) the logged in member needs to be the recipient. + # However, for sending private messages (create, etc) the logged in + # member needs to be the sender. Hence this separate set of + # attributes. + def valid_attributes_for_sender + { + "sender_id" => subject.current_member.id, + "recipient_id" => FactoryGirl.create(:member).id + } end def valid_session @@ -36,6 +51,19 @@ describe NotificationsController do end end + describe "GET new" do + it "assigns a new notification as @notification" do + get :new, {} + assigns(:notification).should be_a_new(Notification) + end + + it "assigns a recipient" do + @recipient = FactoryGirl.create(:member) + get :new, {:recipient_id => @recipient.id } + assigns(:recipient).should be_an_instance_of(Member) + end + end + describe "DELETE destroy" do it "destroys the requested notification" do notification = FactoryGirl.create(:notification, :recipient_id => subject.current_member.id) @@ -51,4 +79,41 @@ describe NotificationsController do end end + describe "POST create" do + describe "with valid params" do + it "creates a new notification" do + expect { + post :create, {:notification => valid_attributes_for_sender} + }.to change(Notification, :count).by(1) + end + + it "assigns a newly created notification as @notification" do + post :create, {:notification => valid_attributes_for_sender} + assigns(:notification).should be_a(Notification) + assigns(:notification).should be_persisted + end + + it "redirects to the recipient's profile" do + @recipient = FactoryGirl.create(:member) + post :create, { :notification => { :recipient_id => @recipient.id } } + response.should redirect_to(@recipient) + end + end + + describe "with invalid params" do + it "assigns a newly created but unsaved notification as @notification" do + # Trigger the behavior that occurs when invalid params are submitted + Notification.any_instance.stub(:save).and_return(false) + post :create, {:notification => {}} + assigns(:notification).should be_a_new(Notification) + end + + it "re-renders the 'new' template" do + # Trigger the behavior that occurs when invalid params are submitted + Notification.any_instance.stub(:save).and_return(false) + post :create, {:notification => {}} + response.should render_template("new") + end + end + end end diff --git a/spec/factories/notifications.rb b/spec/factories/notifications.rb index e0e4fc788..4d6deac12 100644 --- a/spec/factories/notifications.rb +++ b/spec/factories/notifications.rb @@ -1,7 +1,7 @@ # Read about factories at https://github.com/thoughtbot/factory_girl FactoryGirl.define do - factory :notification do + factory :notification, aliases: [:message] do sender recipient subject "MyString" diff --git a/spec/factories/planting.rb b/spec/factories/planting.rb index 6cda6ab21..06499b4a4 100644 --- a/spec/factories/planting.rb +++ b/spec/factories/planting.rb @@ -2,8 +2,9 @@ FactoryGirl.define do factory :planting do garden crop - planted_at Time.now + planted_at Date.today quantity 33 description "This is a *really* good plant." + sunniness 'sun' end end diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index f89574629..04d710ef5 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -7,16 +7,34 @@ describe Ability do @ability = Ability.new(@member) end - it 'member can view their own notifications' do - @notification = FactoryGirl.create(:notification, :recipient => @member) - @ability.should be_able_to(:read, @notification) - end + context "notifications" do + it 'member can view their own notifications' do + @notification = FactoryGirl.create(:notification, :recipient => @member) + @ability.should be_able_to(:read, @notification) + end - it "member can't view someone else's notifications" do - @notification = FactoryGirl.create(:notification, - :recipient => FactoryGirl.create(:member) - ) - @ability.should_not be_able_to(:read, @notification) + it "member can't view someone else's notifications" do + @notification = FactoryGirl.create(:notification, + :recipient => FactoryGirl.create(:member) + ) + @ability.should_not be_able_to(:read, @notification) + end + it "member can't send messages to themself" do + @ability.should_not be_able_to(:create, + FactoryGirl.create(:notification, + :recipient => @member, + :sender => @member + ) + ) + end + it "member can send messages to someone else" do + @ability.should be_able_to(:create, + FactoryGirl.create(:notification, + :recipient => FactoryGirl.create(:member), + :sender => @member + ) + ) + end end context "crop wrangling" do diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb index e8ef4baad..e1f756634 100644 --- a/spec/models/member_spec.rb +++ b/spec/models/member_spec.rb @@ -199,4 +199,40 @@ describe 'member' do end end + context 'confirmed scope' do + before(:each) do + @member1 = FactoryGirl.create(:member) + @member2 = FactoryGirl.create(:member) + end + + it 'sees confirmed members' do + Member.confirmed.count.should == 2 + end + + it 'ignores unconfirmed members' do + @member3 = FactoryGirl.create(:unconfirmed_member) + Member.confirmed.count.should == 2 + end + end + + context 'interesting scope' do + + # active members are defined as: + # 1) confirmed + # 2) ordered by the most recent sign in + it 'finds interesting members' do + @member1 = FactoryGirl.create(:geolocated_member) + @member2 = FactoryGirl.create(:geolocated_member) + @member3 = FactoryGirl.create(:geolocated_member) + @member4 = FactoryGirl.create(:unconfirmed_member) + + @member1.updated_at = 3.days.ago + @member2.updated_at = 2.days.ago + @member3.updated_at = 1.days.ago + + Member.interesting.should eq [ @member3, @member2, @member1 ] + + end + end + end diff --git a/spec/models/planting_spec.rb b/spec/models/planting_spec.rb index 53cc1b7fb..ca3c67c0c 100644 --- a/spec/models/planting_spec.rb +++ b/spec/models/planting_spec.rb @@ -19,6 +19,12 @@ describe Planting do @planting.location.should match /^member\d+'s Springfield Community Garden$/ end + it "sorts plantings in descending order of creation" do + @planting1 = FactoryGirl.create(:planting) + @planting2 = FactoryGirl.create(:planting) + Planting.first.should eq @planting2 + end + it "should have a slug" do @planting.slug.should match /^member\d+-springfield-community-garden-tomato$/ end @@ -33,9 +39,51 @@ describe Planting do @planting.planted_at.should == Time.local(2013, 03, 01) end + it 'should accept blank dates' do + @planting.planted_at_string = '' + @planting.planted_at.should == nil + end + it "should output dates in ISO format" do @planting.planted_at = Time.local(2013, 03, 01) @planting.planted_at_string.should == "2013-03-01" end + it 'should sort in reverse creation order' do + @planting2 = FactoryGirl.create(:planting) + Planting.first.should eq @planting2 + end + + context 'delegation' do + it 'system name' do + @planting.crop_system_name.should eq @planting.crop.system_name + end + it 'wikipedia url' do + @planting.crop_en_wikipedia_url.should eq @planting.crop.en_wikipedia_url + end + it 'default scientific name' do + @planting.crop_default_scientific_name.should eq @planting.crop.default_scientific_name + end + it 'plantings count' do + @planting.crop_plantings_count.should eq @planting.crop.plantings_count + end + end + + it 'should have a sunniness value' do + @planting.sunniness.should eq 'sun' + end + + it 'all three valid sunniness values should work' do + ['sun', 'shade', 'semi-shade', nil, ''].each do |s| + @planting = FactoryGirl.build(:planting, :sunniness => s) + @planting.should be_valid + end + end + + it 'should refuse invalid sunniness values' do + @planting = FactoryGirl.build(:planting, :sunniness => 'not valid') + @planting.should_not be_valid + @planting.errors[:sunniness].should include("not valid is not a valid sunniness value") + end + end diff --git a/spec/views/home/index_spec.rb b/spec/views/home/index_spec.rb index 38b4a4fb8..b75f6b491 100644 --- a/spec/views/home/index_spec.rb +++ b/spec/views/home/index_spec.rb @@ -3,12 +3,33 @@ require 'spec_helper' describe 'home/index.html.haml', :type => "view" do context 'logged out' do before(:each) do + @member = FactoryGirl.create(:geolocated_member) + @member.updated_at = 2.days.ago + @post = FactoryGirl.create(:post, :author => @member) + @planting = FactoryGirl.create(:planting, :garden => @member.gardens.first) + controller.stub(:current_user) { nil } + assign(:interesting_members, [@member]) + assign(:plantings, [@planting]) + assign(:posts, [@post]) render end - it 'should have description' do + it 'has description' do rendered.should contain 'is a community of food gardeners' - rendered.should contain 'We welcome you regardless of your experience, and invite you to be part of our development process.' + end + + it 'show recent posts' do + rendered.should contain @post.subject + end + + it 'show recent plantings' do + rendered.should contain @planting.crop_system_name + rendered.should contain @planting.garden.name + end + + it 'show interesting members' do + rendered.should contain @member.login_name + rendered.should contain @member.location end end @@ -17,11 +38,14 @@ describe 'home/index.html.haml', :type => "view" do @member = FactoryGirl.create(:geolocated_member) controller.stub(:current_user) { @member } sign_in @member + assign(:member, @member) @planting = FactoryGirl.create(:planting, :garden => @member.gardens.first ) + assign(:plantings, [@planting]) @forum = FactoryGirl.create(:forum, :owner => @member) @post = FactoryGirl.create(:post, :author => @member) + assign(:posts, [@post]) @role = FactoryGirl.create(:admin) @member.roles << @role render diff --git a/spec/views/layouts/application_spec.rb b/spec/views/layouts/application_spec.rb index 51db99ef3..48cd360ce 100644 --- a/spec/views/layouts/application_spec.rb +++ b/spec/views/layouts/application_spec.rb @@ -58,9 +58,10 @@ describe 'layouts/application.html.haml', :type => "view" do end it 'includes the analytics code' do - Growstuff::Application.config.analytics_code = 'ANALYTICS' + Growstuff::Application.config.analytics_code = '' render - rendered.should contain 'ANALYTICS' + assert_select "script", :text => 'alert("foo!")' + rendered.should_not contain 'script' end end diff --git a/spec/views/members/index.html.haml_spec.rb b/spec/views/members/index.html.haml_spec.rb index cc6f9401b..3da0b4f40 100644 --- a/spec/views/members/index.html.haml_spec.rb +++ b/spec/views/members/index.html.haml_spec.rb @@ -6,11 +6,9 @@ describe "members/index" do page = 1 per_page = 2 total_entries = 2 + @member = FactoryGirl.create(:geolocated_member) members = WillPaginate::Collection.create(page, per_page, total_entries) do |pager| - pager.replace([ - FactoryGirl.create(:member), - FactoryGirl.create(:member) - ]) + pager.replace([ @member, @member ]) end assign(:members, members) render @@ -20,4 +18,8 @@ describe "members/index" do assert_select "img", :src => /gravatar\.com\/avatar/, :count => 2 end + it 'contains member locations' do + rendered.should contain @member.location + end + end diff --git a/spec/views/members/show.html.haml_spec.rb b/spec/views/members/show.html.haml_spec.rb index 701972107..f141694ec 100644 --- a/spec/views/members/show.html.haml_spec.rb +++ b/spec/views/members/show.html.haml_spec.rb @@ -76,6 +76,10 @@ describe "members/show" do it "contains an edit settings button" do rendered.should contain "Edit Settings" end + + it "contains no send message button" do + rendered.should_not contain "Send Message" + end end context "signed in as different member" do @@ -97,6 +101,10 @@ describe "members/show" do it "contains no edit settings button" do rendered.should_not contain "Edit Settings" end + + it "contains a send message button" do + rendered.should contain "Send Message" + end end context "public member" do @@ -108,6 +116,10 @@ describe "members/show" do it "shows the email address" do rendered.should contain @member.email end + + it "doesn't show a send message button" do + rendered.should_not contain "Send Message" + end end context "geolocations" do diff --git a/spec/views/notifications/new.html.haml_spec.rb b/spec/views/notifications/new.html.haml_spec.rb new file mode 100644 index 000000000..441905ef0 --- /dev/null +++ b/spec/views/notifications/new.html.haml_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe "notifications/new" do + before(:each) do + @recipient = FactoryGirl.create(:member) + @sender = FactoryGirl.create(:member) + assign(:notification, FactoryGirl.create(:notification, :recipient_id => @recipient.id, :sender_id => @sender.id)) +# assign(:forum, Forum.new) + sign_in @sender + controller.stub(:current_user) { @sender} + end + + it "renders new message form" do + render + assert_select "form", :action => notifications_path, :method => "notification" do + assert_select "input#notification_subject", :name => "notification[subject]" + assert_select "textarea#notification_body", :name => "notification[body]" + end + end + + it "tells you who the recipient is" do + render + rendered.should contain @recipient.login_name + end + + it "Tells you to write your message here" do + render + rendered.should contain "Type your message here" + end + + it 'shows markdown help' do + render + rendered.should contain 'Markdown' + end + +end diff --git a/spec/views/plantings/_thumbnail.html.haml_spec.rb b/spec/views/plantings/_thumbnail.html.haml_spec.rb index 3e55d08ea..5abebe8c7 100644 --- a/spec/views/plantings/_thumbnail.html.haml_spec.rb +++ b/spec/views/plantings/_thumbnail.html.haml_spec.rb @@ -25,7 +25,7 @@ describe "plantings/_thumbnail" do end it "renders the date planted" do - rendered.should contain @planting.planted_at.to_s(:date) + rendered.should contain @planting.planted_at.to_s(:default) end it "shows the name of the crop" do diff --git a/spec/views/plantings/new.html.haml_spec.rb b/spec/views/plantings/new.html.haml_spec.rb index d57208dd8..a07273297 100644 --- a/spec/views/plantings/new.html.haml_spec.rb +++ b/spec/views/plantings/new.html.haml_spec.rb @@ -33,6 +33,7 @@ describe "plantings/new" do assert_select "select#planting_crop_id", :name => "planting[crop_id]" assert_select "input#planting_quantity", :name => "planting[quantity]" assert_select "textarea#planting_description", :name => "planting[description]" + assert_select "select#planting_sunniness", :name => "planting[sunniness]" end end diff --git a/spec/views/plantings/show.html.haml_spec.rb b/spec/views/plantings/show.html.haml_spec.rb index 7afb70cda..8eabcd535 100644 --- a/spec/views/plantings/show.html.haml_spec.rb +++ b/spec/views/plantings/show.html.haml_spec.rb @@ -9,6 +9,26 @@ describe "plantings/show" do ) end + it "shows the sunniness" do + controller.stub(:current_user) { nil } + @member = FactoryGirl.create(:member) + create_planting_for(@member) + render + rendered.should contain 'Sun or shade?' + rendered.should contain 'sun' + end + + it "doesn't show sunniness if blank" do + controller.stub(:current_user) { nil } + @member = FactoryGirl.create(:member) + @p = create_planting_for(@member) + @p.sunniness = '' + @p.save + render + rendered.should_not contain 'Sun or shade?' + rendered.should_not contain 'sun' + end + context "no location set" do before(:each) do controller.stub(:current_user) { nil } diff --git a/spec/views/posts/show.html.haml_spec.rb b/spec/views/posts/show.html.haml_spec.rb index aadf31a29..34c21f9e0 100644 --- a/spec/views/posts/show.html.haml_spec.rb +++ b/spec/views/posts/show.html.haml_spec.rb @@ -46,6 +46,7 @@ describe "posts/show" do @post = assign(:post, FactoryGirl.create(:html_post, :author => @author)) @comment = FactoryGirl.create(:comment, :post => @post) + @comments = @post.comments render end @@ -62,6 +63,26 @@ describe "posts/show" do end end + context "when there is more than one comment" do + before(:each) do + @post = assign(:post, + FactoryGirl.create(:html_post, :author => @author)) + @comment1 = FactoryGirl.create(:comment, :post => @post, :body => "F1rst!!!", + :created_at => Date.new(2010, 5, 17)) + @comment3 = FactoryGirl.create(:comment, :post => @post, :body => "Th1rd!!!", + :created_at => Date.new(2012, 5, 17)) + @comment4 = FactoryGirl.create(:comment, :post => @post, :body => "F0urth!!!") + @comment2 = FactoryGirl.create(:comment, :post => @post, :body => "S3c0nd!!1!", + :created_at => Date.new(2011, 5, 17)) + @comments = @post.comments + render + end + + it "shows the oldest comments first" do + rendered.should contain /#{@comment1.body}.*#{@comment2.body}.*#{@comment3.body}.*#{@comment4.body}/m + end + end + context "forum post" do it "shows forum name" do @post = assign(:post,