Merge branch 'dev' into photos/seeds

This commit is contained in:
Brenda Wallace
2019-01-30 16:46:42 +13:00
committed by GitHub
111 changed files with 785 additions and 598 deletions

View File

@@ -51,7 +51,7 @@ GEM
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
addressable (2.5.2)
addressable (2.6.0)
public_suffix (>= 2.0.2, < 4.0)
arel (9.0.0)
ast (2.4.0)
@@ -80,7 +80,7 @@ GEM
uniform_notifier (~> 1.11)
byebug (10.0.2)
cancancan (2.3.0)
capybara (3.12.0)
capybara (3.13.0)
addressable
mini_mime (>= 0.1.3)
nokogiri (~> 1.8)
@@ -294,7 +294,7 @@ GEM
multi_json (1.11.3)
multi_xml (0.6.0)
multipart-post (2.0.0)
newrelic_rpm (5.6.0.349)
newrelic_rpm (6.0.0.351)
nio4r (2.3.1)
nokogiri (1.10.1)
mini_portile2 (~> 2.4.0)

View File

@@ -38,7 +38,6 @@
},
"addons": [
"heroku-postgresql",
"bonsai-elasticsearch",
"memcachier",
"newrelic",
"sendgrid"

View File

@@ -54,4 +54,4 @@ $(document).ready(function() {
$('.btn.toggle.crop-hierarchy').click(function () {
$('.toggle.crop-hierarchy').toggleClass('hide');
});
});
});

View File

@@ -132,11 +132,13 @@ p.stats
padding: 0
border: 1px solid darken($beige, 10%)
border-radius: 4px
.planting-actions
top: -8em
.planting-name
position: relative
top: -1em
.planting-quick-actions
position: absolute
top: 0
right: 2em
dl.planting-attributes
dt

View File

@@ -11,7 +11,7 @@ module Charts
end
def harvested_for
@crop = Crop.find(params[:crop_id])
@crop = Crop.find_by!(slug: params[:crop_slug])
render json: Harvest.joins(:plant_part)
.where(crop: @crop)
.group("plant_parts.name").count(:id)
@@ -20,7 +20,7 @@ module Charts
private
def pie_chart_query(field)
@crop = Crop.find(params[:crop_id])
@crop = Crop.find_by!(slug: params[:crop_slug])
render json: Planting.where(crop: @crop)
.where.not(field.to_sym => nil)
.where.not(field.to_sym => '')

View File

@@ -49,7 +49,7 @@ class CropsController < ApplicationController
end
def show
@crop = Crop.includes(:scientific_names, plantings: :photos).find(params[:id])
@crop = Crop.includes(:scientific_names, plantings: :photos).find_by!(slug: params[:slug])
@posts = @crop.posts.order(created_at: :desc).paginate(page: params[:page])
# respond_with(@crop)
respond_to do |format|
@@ -67,6 +67,7 @@ class CropsController < ApplicationController
end
def edit
@crop = Crop.find_by!(slug: params[:slug])
@crop.alternate_names.build if @crop.alternate_names.blank?
@crop.scientific_names.build if @crop.scientific_names.blank?
end
@@ -87,6 +88,7 @@ class CropsController < ApplicationController
end
def update
@crop = Crop.find_by!(slug: params[:slug])
previous_status = @crop.approval_status
@crop.creator = current_member if previous_status == "pending"

View File

@@ -1,11 +1,11 @@
class FollowsController < ApplicationController
before_action :authenticate_member!
before_action :set_member, only: %i(index followers)
load_and_authorize_resource
skip_load_resource only: :create
# POST /follows
def create
@follow = current_member.follows.build(followed_id: follow_params[:followed_id])
@follow = current_member.follows.build(followed: Member.find(params[:followed]))
if @follow.save
flash[:notice] = "Followed #{@follow.followed.login_name}"
@@ -15,19 +15,30 @@ class FollowsController < ApplicationController
redirect_back fallback_location: root_path
end
# DELETE /follows/1
def destroy
@follow = current_member.follows.find(follow_params[:id])
unfollowed_name = @follow.followed.login_name
@follow = current_member.follows.find(params[:id])
@unfollowed = @follow.followed
@follow.destroy
flash[:notice] = "Unfollowed #{unfollowed_name}"
redirect_to root_path
flash[:notice] = "Unfollowed #{@unfollowed.login_name}"
redirect_to @unfollowed
end
def index
@follows = @member.followed.paginate(page: params[:page])
end
def followers
@followers = @member.followers.paginate(page: params[:page])
end
private
def set_member
@member = Member.confirmed.find(params[:member_slug])
end
def follow_params
params.permit(:id, :followed_id, :follower_id, :authenticity_token, :_method)
params.permit(:id, :followed, :follower)
end
end

View File

@@ -7,9 +7,12 @@ class GardensController < ApplicationController
# GET /gardens
# GET /gardens.json
def index
@owner = Member.find_by(slug: params[:owner])
@owner = Member.find_by(slug: params[:member_slug])
@show_all = params[:all] == '1'
@gardens = gardens
@gardens = @gardens.active unless @show_all
@gardens = @gardens.where(owner: @owner) if @owner.present?
@gardens = @gardens.joins(:owner).order(:name).paginate(page: params[:page])
respond_with(@gardens)
end
@@ -57,7 +60,7 @@ class GardensController < ApplicationController
def destroy
@garden.destroy
flash[:notice] = I18n.t('gardens.deleted')
redirect_to(gardens_by_owner_path(owner: @garden.owner))
redirect_to(member_gardens_path(@garden.owner))
end
private
@@ -66,10 +69,4 @@ class GardensController < ApplicationController
params.require(:garden).permit(:name, :slug, :description, :active,
:location, :latitude, :longitude, :area, :area_unit)
end
def gardens
g = @owner ? @owner.gardens : Garden.all
g = g.active unless @show_all
g.joins(:owner).order(:name).paginate(page: params[:page])
end
end

View File

@@ -7,12 +7,17 @@ class HarvestsController < ApplicationController
responders :flash
def index
@owner = Member.find_by(slug: params[:owner]) if params[:owner]
@crop = Crop.find_by(slug: params[:crop]) if params[:crop]
@planting = Planting.find_by(slug: params[:planting_id]) if params[:planting_id]
@owner = Member.find_by(slug: params[:member_slug])
@crop = Crop.find_by(slug: params[:crop_slug])
@planting = Planting.find_by(slug: params[:planting_id])
@harvests = @harvests.where(owner: @owner) if @owner.present?
@harvests = @harvests.where(crop: @crop) if @crop.present?
@harvests = @harvests.where(planting: @planting) if @planting.present?
@harvests = @harvests.order(harvested_at: :desc).joins(:owner, :crop).paginate(page: params[:page])
@harvests = harvests
@filename = csv_filename
respond_with(@harvests)
end
@@ -67,23 +72,11 @@ class HarvestsController < ApplicationController
.where('(finished_at IS NULL OR finished_at >= ?)', @harvest.harvested_at)
end
def harvests
if @owner
@owner.harvests
elsif @crop
@crop.harvests
elsif @planting
@planting.harvests
else
Harvest.all
end.order(harvested_at: :desc).joins(:owner, :crop).paginate(page: params[:page])
end
def csv_filename
specifics = if @owner
"#{@owner.login_name}-"
"#{@owner.to_param}-"
elsif @crop
"#{@crop.name}-"
"#{@crop.to_param}-"
end
"Growstuff-#{specifics}Harvests-#{Time.zone.now.to_s(:number)}.csv"
end

View File

@@ -13,7 +13,7 @@ class MembersController < ApplicationController
end
def show
@member = Member.confirmed.find(params[:id])
@member = Member.confirmed.find_by!(slug: params[:slug])
@twitter_auth = @member.auth('twitter')
@flickr_auth = @member.auth('flickr')
@facebook_auth = @member.auth('facebook')
@@ -38,16 +38,6 @@ class MembersController < ApplicationController
end
end
def view_follows
@member = Member.confirmed.find(params[:login_name])
@follows = @member.followed.paginate(page: params[:page])
end
def view_followers
@member = Member.confirmed.find(params[:login_name])
@followers = @member.followers.paginate(page: params[:page])
end
EMAIL_TYPE_STRING = {
send_notification_email: "direct message notifications",
send_planting_reminder: "planting reminders"

View File

@@ -27,7 +27,7 @@ class NotificationsController < ApplicationController
# GET /notifications/1/reply
def reply
@notification = Notification.new
@sender_notification = Notification.find_by(id: params[:id], recipient: current_member)
@sender_notification = Notification.find_by!(id: params[:notification_id], recipient: current_member)
@sender_notification.read = true
@sender_notification.save
@recipient = @sender_notification.sender

View File

@@ -10,17 +10,20 @@ class PlantingsController < ApplicationController
responders :flash
def index
@owner = Member.find_by(slug: params[:owner]) if params[:owner]
@crop = Crop.find_by(slug: params[:crop]) if params[:crop]
@owner = Member.find_by(slug: params[:member_slug]) if params[:member_slug]
@crop = Crop.find_by(slug: params[:crop_slug]) if params[:crop_slug]
@show_all = params[:all] == '1'
@plantings = plantings
@plantings = @plantings.where(owner: @owner) if @owner.present?
@plantings = @plantings.where(crop: @crop) if @crop.present?
specifics = if @owner
"#{@owner.login_name}-"
elsif @crop
"#{@crop.name}-"
end
@plantings = @plantings.active unless params[:all] == '1'
@plantings = @plantings.joins(:owner, :crop, :garden)
.order(created_at: :desc)
.includes(:crop, :owner, :garden)
.paginate(page: params[:page])
@filename = "Growstuff-#{specifics}Plantings-#{Time.zone.now.to_s(:number)}.csv"
@@ -104,4 +107,12 @@ class PlantingsController < ApplicationController
.includes(:crop, :owner, :garden)
.paginate(page: params[:page])
end
def specifics
if @owner.present?
"#{@owner.to_param}-"
elsif @crop.present?
"#{@crop.to_param}-"
end
end
end

View File

@@ -8,9 +8,13 @@ class SeedsController < ApplicationController
# GET /seeds
# GET /seeds.json
def index
@owner = Member.find_by(slug: params[:owner])
@crop = Crop.find_by(slug: params[:crop])
@seeds = seeds(owner: @owner, crop: @crop)
@owner = Member.find_by(slug: params[:member_slug]) if params[:member_slug].present?
@crop = Crop.find_by(slug: params[:crop_slug]) if params[:crop_slug].present?
@seeds = @seeds.where(owner: @owner) if @owner.present?
@seeds = @seeds.where(crop: @crop) if @crop.present?
@seeds = @seeds.order(created_at: :desc).includes(:owner, :crop).paginate(page: params[:page])
@filename = csv_filename
respond_with(@seeds)
@@ -65,19 +69,9 @@ class SeedsController < ApplicationController
)
end
def seeds(owner: nil, crop: nil)
if owner
owner.seeds
elsif crop
crop.seeds
else
Seed
end.order(created_at: :desc).includes(:owner, :crop).paginate(page: params[:page])
end
def csv_filename
if @owner
"Growstuff-#{@owner}-Seeds-#{Time.zone.now.to_s(:number)}.csv"
"Growstuff-#{@owner.to_param}-Seeds-#{Time.zone.now.to_s(:number)}.csv"
else
"Growstuff-Seeds-#{Time.zone.now.to_s(:number)}.csv"
end

View File

@@ -70,8 +70,8 @@ module ApplicationHelper
def show_inactive_tickbox_path(type, owner, show_all)
all = show_all ? '' : 1
if owner
return plantings_by_owner_path(owner: owner.slug, all: all) if type == 'plantings'
return gardens_by_owner_path(owner: owner.slug, all: all) if type == 'gardens'
return member_plantings_path(owner, all: all) if type == 'plantings'
return member_gardens_path(owner, all: all) if type == 'gardens'
end
return plantings_path(all: all) if type == 'plantings'

View File

@@ -10,7 +10,7 @@ module AutoSuggestHelper
end
resource = resource.class.name.downcase
source_path = Rails.application.routes.url_helpers.send("#{source}s_search_path")
source_path = Rails.application.routes.url_helpers.send("search_#{source}s_path")
%(
<input id="#{source}" class="auto-suggest #{options[:class]}"

View File

@@ -0,0 +1,101 @@
module ButtonsHelper
include IconsHelper
def garden_plant_something_button(garden)
link_to new_planting_path(garden_id: garden.id), class: "btn btn-default btn-xs btn-primary" do
planting_icon + ' ' + t('buttons.plant_something_here')
end
end
def garden_mark_active_button(garden)
link_to t('buttons.mark_as_active'),
garden_path(garden, garden: { active: 1 }),
method: :put, class: 'btn btn-default btn-xs'
end
def garden_mark_inactive_button(garden)
link_to t('buttons.mark_as_inactive'),
garden_path(garden, garden: { active: 0 }),
method: :put, class: 'btn btn-default btn-xs',
data: { confirm: 'All plantings associated with this garden will be marked as finished. Are you sure?' }
end
def crop_edit_button(crop)
edit_button(edit_crop_path(crop))
end
def seed_edit_button(seed)
edit_button(edit_seed_path(seed))
end
def harvest_edit_button(harvest)
edit_button(edit_harvest_path(harvest))
end
def garden_edit_button(garden)
edit_button(edit_garden_path(garden))
end
def planting_edit_button(planting)
edit_button(edit_planting_path(planting))
end
def planting_finish_button(planting)
return unless can?(:edit, planting) || planting.finished
link_to planting_path(planting, planting: { finished: 1 }),
method: :put, class: 'btn btn-default btn-xs append-date' do
finished_icon + ' ' + t('buttons.mark_as_finished')
end
end
def planting_harvest_button(planting)
return unless planting.active? && can?(:create, Harvest) && can?(:edit, planting)
link_to new_planting_harvest_path(planting), class: "btn btn-default btn-xs" do
harvest_icon + ' ' + t('buttons.harvest')
end
end
def planting_save_seeds_button(planting)
return unless can?(:edit, planting)
link_to new_planting_seed_path(planting), class: "btn btn-default btn-xs" do
seed_icon + ' ' + t('buttons.save_seeds')
end
end
def add_photo_button(model)
return unless can?(:edit, model) && can?(:create, Photo)
link_to new_photo_path(id: model.id, type: model_type_for_photo(model)),
class: "btn btn-default btn-xs" do
photo_icon + ' ' + t('buttons.add_photo')
end
end
def edit_button(path)
link_to path, class: "btn btn-default btn-xs" do
edit_icon + ' ' + t('buttons.edit')
end
end
def delete_button(model, message: 'are_you_sure')
return unless can? :destroy, model
link_to model, method: :delete, data: { confirm: t(message) }, class: 'btn btn-default btn-xs' do
delete_icon + ' ' + t('buttons.delete')
end
end
private
def model_type_for_photo(model)
ActiveModel::Name.new(model.class).to_s.downcase
end
def button(path, button_title, icon, size = 'btn-xs')
link_to path, class: "btn btn-default #{size}" do
icon + ' ' + button_title
end
end
end

View File

@@ -0,0 +1,34 @@
module IconsHelper
include FontAwesome::Sass::Rails::ViewHelpers
def garden_icon
icon('far', 'square')
end
def planting_icon
icon('fas', 'seedling')
end
def harvest_icon
icon('fas', 'carrot')
end
def seed_icon
icon('fas', 'heart')
end
def finished_icon
icon('fas', 'calendar')
end
def edit_icon
icon('far', 'edit')
end
def delete_icon
icon('fas', 'trash-alt')
end
def photo_icon
icon('fas', 'camera-retro')
end
end

View File

@@ -5,7 +5,7 @@ module NotificationsHelper
new_comment_url(post_id: notification.post.id)
else
# by default, reply link sends a PM in return
reply_notification_url(notification)
notification_reply_url(notification)
end
end
end

View File

@@ -113,6 +113,10 @@ class Crop < ApplicationRecord
name
end
def to_param
slug
end
def default_scientific_name
scientific_names.first.name unless scientific_names.empty?
end
@@ -155,12 +159,7 @@ class Crop < ApplicationRecord
end
def interesting?
min_plantings = 3 # needs this many plantings to be interesting
min_photos = 3 # needs this many photos to be interesting
return false unless photos.size >= min_photos
return false unless plantings_count >= min_plantings
true
photos.size >= 3 || plantings_count >= 3
end
def pending?

View File

@@ -18,8 +18,9 @@ class Garden < ApplicationRecord
scope :active, -> { where(active: true) }
scope :inactive, -> { where(active: false) }
validates :location,
length: { maximum: 255 }
validates :location, length: { maximum: 255 }
validates :slug, uniqueness: true
validates :name, uniqueness: { scope: :owner_id }
validates :name,
format: {

View File

@@ -106,6 +106,10 @@ class Member < ApplicationRecord
login_name
end
def to_param
slug
end
def role?(role_sym)
roles.any? { |r| r.name.gsub(/\s+/, "_").underscore.to_sym == role_sym }
end

View File

@@ -33,6 +33,7 @@ class Planting < ApplicationRecord
##
## Scopes
default_scope { joins(:owner) } # Ensures the owner still exists
scope :active, -> { where(finished_at: nil) }
scope :interesting, -> { has_photos.one_per_owner.order(planted_at: :desc) }
scope :recent, -> { order(created_at: :desc) }
scope :one_per_owner, lambda {

View File

@@ -1,9 +1,16 @@
.crop-actions
- if can? :create, Planting
= link_to "Plant this", new_planting_path(crop_id: crop.id), class: 'btn btn-default'
.btn-group
- if can? :create, Planting
= link_to new_planting_path(crop_id: crop.id), class: 'btn btn-default' do
= planting_icon
= t('buttons.plant_crop', crop_name: crop.name)
- 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, Harvest
= link_to new_harvest_path(crop_id: crop.id), class: 'btn btn-default' do
= harvest_icon
= t('buttons.harvest_crop', crop_name: crop.name)
- if can? :create, Seed
= link_to new_seed_path(crop_id: crop.id), class: 'btn btn-default' do
= seed_icon
= t('buttons.add_seed_to_stash', crop_name: crop.name)

View File

@@ -9,7 +9,7 @@
= link_to "#{seed.owner} will trade #{seed.tradable_to}.", seed_path(seed)
= render partial: 'members/location', locals: { member: seed.owner }
%p
= link_to "View all #{crop.name} seeds", seeds_by_crop_path(crop)
= link_to "View all #{crop.name} seeds", crop_seeds_path(crop)
%p
= link_to "Purchase seeds via Ebay",
crop_ebay_seeds_url(crop),

View File

@@ -12,7 +12,7 @@
= distance_of_time_in_words(harvest.created_at, Time.zone.now)
ago.
%p
= link_to "View all #{crop.name} harvests", harvests_by_crop_path(crop)
= link_to "View all #{crop.name} harvests", crop_harvests_path(crop)
- if crop.approved?
- if current_member
%p= link_to "Harvest #{crop.name}", new_harvest_path(crop_id: crop.id)

View File

@@ -31,6 +31,6 @@
days after planting
- if can? :create, Planting
= link_to 'Plant this', new_planting_path(params: { crop_id: crop.id }), class: 'btn btn-primary'
= link_to "Plant #{crop.name}", new_planting_path(params: { crop_id: crop.id }), class: 'btn btn-primary'
- if can? :create, Seed
= link_to 'Add seeds to stash', new_seed_path(params: { crop_id: crop.id }), class: 'btn btn-primary'
= link_to "Add #{crop.name} seeds to stash", new_seed_path(params: { crop_id: crop.id }), class: 'btn btn-primary'

View File

@@ -19,4 +19,4 @@
.col-xs-6.col-md-2
= render "photos/thumbnail", photo: p
.row
= link_to "more photos", crop_photos_path(crop_id: crop.id)
= link_to "more photos", crop_photos_path(crop)

View File

@@ -12,7 +12,7 @@
= distance_of_time_in_words(planting.created_at, Time.zone.now)
ago.
%p
= link_to "View all #{crop.name} plantings", plantings_by_crop_path(crop)
= link_to "View all #{crop.name} plantings", crop_plantings_path(crop)
- if crop.approved?
- if current_member
%p= link_to "Plant #{crop.name}", new_planting_path(crop_id: crop.id)

View File

@@ -0,0 +1,9 @@
= form_tag search_crops_path, method: :get, id: 'navbar-search' do
= label_tag :term, "Search crop database:", class: 'sr-only'
.input
.input-group
= text_field_tag 'term', nil, class: 'search-query input-medium form-control', placeholder: 'Search crops'
.input-group-btn
%button.btn.btn-default{ style: "height: 34px;" }
= submit_tag "Search", class: 'btn sr-only'
%span.glyphicon.glyphicon-search

View File

@@ -4,11 +4,6 @@
You are a
= succeed "." do
%strong CROP WRANGLER
%p
- if can? :edit, crop
= link_to 'Edit crop', edit_crop_path(crop), class: 'btn btn-default btn-xs'
- if can? :destroy, crop
= link_to 'Delete crop', crop,
method: :delete,
data: { confirm: 'Are you sure?' },
class: 'btn btn-default btn-xs'
%p= crop_edit_button(crop) if can? :edit, crop
%p= delete_button(crop) if can? :destroy, crop

View File

@@ -7,7 +7,7 @@
things to consider when suggesting a new crop:
%ul
%li
First, you might want to #{link_to 'search our crops', crops_search_path}
First, you might want to #{link_to 'search our crops', search_crops_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

View File

@@ -6,7 +6,7 @@
- content_for :title, "Crop search"
%div
= form_tag crops_search_path, method: :get, id: 'crop-search', class: 'form-inline' do
= form_tag search_crops_path, method: :get, id: 'crop-search', class: 'form-inline' do
.form-group
= label_tag :term, "Search crops:", class: 'sr-only'
= text_field_tag 'term', nil,

View File

@@ -21,9 +21,6 @@
.col-md-9
.row
.col-md-12
- if member_signed_in?
= display_seed_availability(@current_member, @crop)
= link_to "View your seeds", seeds_by_owner_path(owner: current_member.slug)
%h2
- if !@crop.plantings.empty?
@@ -34,7 +31,6 @@
- else
Nobody is growing this yet. You could be the first!
.row
.col-md-12
%h2 Predictions
@@ -47,14 +43,13 @@
.row
.col-md-3
%h2 Sunniness
= pie_chart crop_sunniness_path(@crop), legend: "bottom"
= pie_chart crop_sunniness_path(@crop, format: :json), legend: "bottom"
.col-md-3
%h2 Planted from
= pie_chart crop_planted_from_path(@crop), legend: "bottom"
= pie_chart crop_planted_from_path(@crop, format: :json), legend: "bottom"
.col-md-3
%h2 Harvested for
= pie_chart crop_harvested_for_path(@crop), legend: "bottom"
= pie_chart crop_harvested_for_path(@crop, format: :json), legend: "bottom"
.row
.col-md-12
@@ -92,6 +87,24 @@
= render partial: 'wrangle', locals: { crop: @crop }
%p
%li
= link_to crop_seeds_path(@crop) do
View all #{@crop.name} seeds
(#{@crop.seeds.size})
%li
= link_to crop_plantings_path(@crop) do
View all #{@crop.name} plantings
(#{@crop.plantings.size})
%li
= link_to crop_harvests_path(@crop) do
View all #{@crop.name} harvests
(#{@crop.harvests.size})
- if member_signed_in?
%p
= link_to member_seeds_path(current_member, crop_slug: @crop.slug) do
= display_seed_availability(@current_member, @crop)
%h4 How to grow #{@crop.name.pluralize}
= render 'grown_for', crop: @crop

View File

@@ -5,7 +5,7 @@
%li= link_to "Requests for new crops", 'http://growstuff.org/posts/skud-20130319-requests-for-new-crops'
%li= link_to "Crop wrangler guidelines", "http://wiki.growstuff.org/index.php/Crop_wrangling"
%li= link_to "crop-wranglers mailing list", "http://lists.growstuff.org/listinfo/crop-wranglers"
%li= link_to "Full crop hierarchy", crops_hierarchy_path
%li= link_to "Full crop hierarchy", hierarchy_crops_path
%li= link_to "Add Crop", new_crop_path
.crop_wranglers

View File

@@ -1,29 +1,14 @@
.garden-actions
- if can?(:edit, garden)
= garden_plant_something_button(garden) if garden.active
.btn-group
- if garden.active
= link_to new_planting_path(garden_id: garden.id), class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-grain{ title: "Plant" }
Plant something
= link_to "Mark as inactive", garden_path(garden, garden: { active: 0 }),
method: :put, class: 'btn btn-default btn-xs',
data: { confirm: 'All plantings associated with this garden will be marked as finished. Are you sure?' }
= garden_mark_inactive_button(garden)
- else
= link_to "Mark as active", garden_path(garden, garden: { active: 1 }),
method: :put
= render 'shared/buttons/edit', path: edit_garden_path(garden)
= garden_mark_active_button(garden)
- if can?(:edit, garden) && can?(:create, Photo)
= link_to new_photo_path(type: "garden", id: garden.id),
class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-camera{ title: "Add photo" }
Add photo
= garden_edit_button(garden)
= add_photo_button(garden)
- if can?(:destroy, garden)
.pull-right
= link_to garden_path(garden),
method: :delete,
data: { confirm: 'All plantings associated with this garden will also be deleted. Are you sure?' },
class: 'btn btn-default btn-xs', id: 'delete_garden_link' do
%span.glyphicon.glyphicon-trash{ title: "Delete" }
Delete
= delete_button(garden, message: 'All plantings associated with this garden will also be deleted. Are you sure?')

View File

@@ -1,10 +0,0 @@
- content_for :buttonbar do
- if current_member
= link_to 'My Gardens', gardens_by_owner_path(owner: current_member.slug), class: 'btn btn-default'
= link_to "Everyone's gardens", gardens_path, class: 'btn btn-default'
- if can?(:create, Garden)
= link_to 'Add a garden', new_garden_path, class: 'btn btn-default'
- unless current_member
= render 'shared/signin_signup', to: 'add a new garden'

View File

@@ -1,6 +1,6 @@
- content_for :title, @owner ? "#{@owner}'s gardens" : "Everyone's gardens"
= render 'nav'
= render 'layouts/nav', model: Garden
= link_to gardens_active_tickbox_path(@owner, @show_all) do
= check_box_tag 'active', 'all', @show_all

View File

@@ -14,11 +14,11 @@
= javascript_include_tag "charts"
= javascript_include_tag "https://www.gstatic.com/charts/loader.js"
-content_for(:buttonbar) do
= render 'gardens/actions', garden: @garden
.row
.col-md-9
= render 'gardens/actions', garden: @garden
- unless @garden.active
.alert.alert-warning
This garden is inactive.
@@ -57,7 +57,7 @@
- if @finished_plantings.size.positive?
- @finished_plantings.each do |planting|
.col-xs-6.col-md-2
= render partial: "plantings/thumbnail", locals: { planting: planting }
= render "plantings/thumbnail", planting: planting
- else
%p Nothing has been planted here.
.col-md-3

View File

@@ -1,7 +1,5 @@
.harvest-actions
- if can?(:edit, harvest) || can?(:destroy, harvest)
.btn-group
- if can? :edit, harvest
= render 'shared/buttons/edit', path: edit_harvest_path(harvest)
- if can? :destroy, harvest
.pull-right= render 'shared/buttons/delete', path: harvest_path(harvest)
.btn-group
= harvest_edit_button(harvest) if can? :edit, harvest
= add_photo_button(harvest)
= delete_button(harvest)

View File

@@ -1,15 +0,0 @@
%p
- if can? :create, Harvest
- if @planting && @planting.owner == current_member
= link_to 'Add harvest', new_planting_harvest_path(planting: @planting), class: 'btn btn-primary'
- elsif @owner
%p
- if @owner == current_member
= link_to 'Add harvest', new_harvest_path, class: 'btn btn-primary'
= link_to "View everyone's harvests", harvests_path, class: 'btn btn-default'
- else # everyone's harvests
= link_to 'Add harvest', new_harvest_path, class: 'btn btn-primary'
- if current_member
= link_to 'View your harvests', harvests_by_owner_path(owner: current_member.slug), class: 'btn btn-default'
- else
= render partial: 'shared/signin_signup', locals: { to: 'track your harvests' }

View File

@@ -7,7 +7,8 @@
#{ENV['GROWSTUFF_SITE_NAME']} helps you track what you're
harvesting from your home garden and see how productive it is.
= render "nav"
= render 'layouts/nav', model: Harvest
.pagination
= page_entries_info @harvests
= will_paginate @harvests
@@ -24,9 +25,9 @@
%ul.list-inline
%li The data on this page is available in the following formats:
- if @owner
%li= link_to "RSS", harvests_by_owner_path(@owner, format: 'rss')
%li= link_to "CSV", harvests_by_owner_path(@owner, format: 'csv')
%li= link_to "JSON", harvests_by_owner_path(@owner, format: 'json')
%li= link_to "RSS", member_harvests_path(@owner, format: 'rss')
%li= link_to "CSV", member_harvests_path(@owner, format: 'csv')
%li= link_to "JSON", member_harvests_path(@owner, format: 'json')
- else
%li= link_to "RSS", harvests_path(format: 'rss')
%li= link_to "CSV", harvests_path(format: 'csv')

View File

@@ -1,3 +1,3 @@
- content_for :title, "New Harvest"
- content_for :title, t('harvests.harvest_something')
= render 'form'

View File

@@ -8,13 +8,16 @@
= tag("meta", property: "og:url", content: request.original_url)
= tag("meta", property: "og:site_name", content: ENV['GROWSTUFF_SITE_NAME'])
-content_for(:buttonbar) do
= render 'harvests/actions', harvest: @harvest
.row
.col-md-6
%p
%b Owner:
= link_to @harvest.owner, @harvest.owner
&mdash;
= link_to "view all #{@harvest.owner}'s harvests", harvests_by_owner_path(owner: @harvest.owner.slug)
= link_to "view all #{@harvest.owner}'s harvests", member_harvests_path(@harvest.owner)
%p
%b Plant part:
- if @harvest.plant_part
@@ -32,7 +35,6 @@
%b Quantity:
= display_quantity(@harvest)
= render 'harvests/actions', harvest: @harvest
.col-md-6
= render partial: "crops/index_card", locals: { crop: @harvest.crop }

View File

@@ -1,16 +1,9 @@
.homepage.row
.col-md-12
- if member_signed_in?
%h1= t('.welcome', site_name: ENV['GROWSTUFF_SITE_NAME'], member_name: current_member)
- content_for :title, t('.welcome', site_name: ENV['GROWSTUFF_SITE_NAME'], member_name: current_member)
= render 'stats'
%p
.btn-group
= link_to t('.plant'), new_planting_path, class: 'btn btn-default'
= link_to t('.harvest'), new_harvest_path, class: 'btn btn-default'
= link_to t('.add_seeds'), new_seed_path, class: 'btn btn-default'
= link_to t('.post'), new_post_path, class: 'btn btn-default'
- else
.hidden-xs
.jumbotron

View File

@@ -17,15 +17,7 @@
alt: ENV['GROWSTUFF_SITE_NAME'])
.form.navbar-form.pull-left
= form_tag crops_search_path, method: :get, id: 'navbar-search' do
= label_tag :term, "Search crop database:", class: 'sr-only'
.input
.input-group
= text_field_tag 'term', nil, class: 'search-query input-medium form-control', placeholder: 'Search crops'
.input-group-btn
%button.btn.btn-default{ style: "height: 34px;" }
= submit_tag "Search", class: 'btn sr-only'
%span.glyphicon.glyphicon-search
= render 'crops/search_bar'
.navbar-collapse.collapse#navbar-collapse
%ul.nav.navbar-nav.navbar-right
@@ -58,11 +50,11 @@
%b.caret
%ul.dropdown-menu
%li= link_to t('.profile'), member_path(current_member)
%li= link_to t('.gardens'), gardens_by_owner_path(owner: current_member.slug)
%li= link_to t('.plantings'), plantings_by_owner_path(owner: current_member.slug)
%li= link_to t('.harvest'), harvests_by_owner_path(owner: current_member.slug)
%li= link_to t('.seeds'), seeds_by_owner_path(owner: current_member.slug)
%li= link_to t('.posts'), posts_by_author_path(author: current_member.slug)
%li= link_to t('.gardens'), member_gardens_path(current_member)
%li= link_to t('.plantings'), member_plantings_path(current_member)
%li= link_to t('.harvest'), member_harvests_path(current_member)
%li= link_to t('.seeds'), member_seeds_path(current_member)
%li= link_to t('.posts'), member_posts_path(current_member)
%li
- if current_member.notifications.unread_count.positive?
= link_to(t('.inbox_unread', unread_count: current_member.notifications.unread_count),

View File

@@ -0,0 +1,14 @@
- content_for :buttonbar do
- if current_member.present?
= link_to url_for([current_member, model]), class: 'btn btn-default' do
My #{model.model_name.human.pluralize}
= link_to model, class: 'btn btn-default' do
Everyone's #{model.model_name.human.pluralize}
- if can?(:create, model)
= link_to url_for([model, action: :new]), class: 'btn btn-default' do
Add a #{model.model_name.human}
- unless current_member
= render 'shared/signin_signup', to: 'add a new seed'

View File

@@ -7,20 +7,27 @@
#maincontainer
.row
.col-md-12
.col-md-6
- if content_for?(:title)
%h1#title
= yield(:title)
- if content_for?(:subtitle)
%small= yield(:subtitle)
- if content_for?(:buttonbar)
.btn-group.layout-actions= yield(:buttonbar)
.btn-group.layout-actions
= yield(:buttonbar)
.col-md-6
= render 'shared/global_actions'
.row
.col-md-12
= render partial: "shared/flash_messages", flash: flash
= yield
%footer
= render partial: "layouts/footer"
= render "layouts/footer"
/
Javascripts
\==================================================

View File

@@ -2,4 +2,4 @@
- if member.location.blank?
unknown location
- else
= link_to member.location, place_path(place: member.location, anchor: "members")
= link_to member.location, place_path(member.location, anchor: "members")

View File

@@ -10,22 +10,22 @@
%ul.activity-list
%li
- if !member.plantings.empty?
= link_to localize_plural(member.plantings, Planting), plantings_by_owner_path(owner: member)
= link_to localize_plural(member.plantings, Planting), member_plantings_path(member)
- else
0 plantings
%li
- if !member.harvests.empty?
= link_to localize_plural(member.harvests, Harvest), harvests_by_owner_path(owner: member)
= link_to localize_plural(member.harvests, Harvest), member_harvests_path(member)
- else
0 harvests
%li
- if !member.seeds.empty?
= link_to localize_plural(member.seeds, Seed), seeds_by_owner_path(owner: member)
= link_to localize_plural(member.seeds, Seed), member_seeds_path(member)
- else
0 seeds
%li
- if !member.posts.empty?
= link_to localize_plural(member.posts, Post), posts_by_author_path(author: member)
= link_to localize_plural(member.posts, Post), member_posts_path(member)
- else
0 posts

View File

@@ -7,16 +7,22 @@
= tag("meta", property: "og:type", content: "profile")
= tag("meta", property: "og:url", content: request.original_url)
= tag("meta", property: "og:site_name", content: ENV['GROWSTUFF_SITE_NAME'])
- content_for :buttonbar do
- if can? :update, @member
= link_to 'Edit profile', edit_member_registration_path, class: 'btn btn-default pull-right'
- if can?(:create, Notification) && current_member != @member
= link_to 'Send message', new_notification_path(recipient_id: @member.id), class: 'btn btn-default pull-right'
%p.btn-group
- if can? :update, @member
= link_to edit_member_registration_path, class: 'btn btn-default pull-right' do
= edit_icon
= t('members.edit_profile')
- if can?(:create, Notification) && current_member != @member
= link_to 'Send message', new_notification_path(recipient_id: @member.id), class: 'btn btn-default'
- if current_member && current_member != @member # must be logged in, can't follow yourself
- follow = current_member.get_follow(@member)
- if !follow && can?(:create, Follow) # not already following
= link_to 'Follow', follows_path(followed_id: @member.id), method: :post, class: 'btn btn-default pull-right'
= link_to 'Follow', follows_path(followed: @member), method: :post, class: 'btn btn-default pull-right'
- if follow && can?(:destroy, follow) # already following
= link_to 'Unfollow', follow_path(follow), method: :delete, class: 'btn btn-default pull-right'

View File

@@ -2,6 +2,6 @@
- if can?(:edit, @photo) && can?(:destroy, @photo)
%p
- if can?(:edit, @photo)
= render 'shared/buttons/edit', path: edit_photo_path(@photo)
= edit_button(@photo)
- if can?(:destroy, @photo)
= render 'shared/buttons/delete', path: photo_path(@photo)
= delete_button(@photo)

View File

@@ -1,4 +1,4 @@
- if can? :edit, photo
= link_to photo_associations_path(photo_id: photo.id, type: type, id: thing.id),
method: 'delete', class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-remove{ title: "Remove link" }
= delete_icon

View File

@@ -1,12 +1,13 @@
- if can?(:edit, planting)
.btn-group.planting-actions
= render 'shared/buttons/edit', path: edit_planting_path(planting)
= render 'shared/buttons/add_photo', path: new_photo_path(id: planting.id, type: 'planting')
.planting-actions
.btn-group
= planting_edit_button(planting)
= add_photo_button(planting)
- if planting.active?
= render 'shared/buttons/finish_planting', planting: planting
= render 'shared/buttons/harvest_planting', planting: planting
= render 'shared/buttons/save_seeds', planting: planting
- if planting.active?
= planting_finish_button(planting)
= planting_harvest_button(planting)
= planting_save_seeds_button(planting)
- if can? :destroy, planting
= render 'shared/buttons/delete', path: planting
= delete_button(planting)

View File

@@ -1,20 +1,21 @@
// Finish times
- if planting.finish_is_predicatable?
- if planting.super_late?
%span.badge.badge-super-late= t('.super_late')
= render 'shared/buttons/finish_planting', planting: planting
- elsif planting.late?
%span.badge.badge-late= t('.late_finishing')
- else
%span.badge
= days_from_now_to_finished(planting)
= t('.days_until_finished')
- unless planting.finished?
// Finish times
- if planting.finish_is_predicatable?
- if planting.super_late?
%span.badge.badge-super-late= t('.super_late')
= planting_finish_button(planting)
- elsif planting.late?
%span.badge.badge-late= t('.late_finishing')
- else
%span.badge
= days_from_now_to_finished(planting)
= t('.days_until_finished')
// Harvest times
- unless planting.super_late?
- if planting.harvest_time?
%span.badge.badge-harvest= t('.harvesting_now')
- elsif planting.before_harvest_time?
%span.badge
= days_from_now_to_first_harvest(planting)
= t('.days_until_harvest')
// Harvest times
- unless planting.super_late?
- if planting.harvest_time?
%span.badge.badge-harvest= t('.harvesting_now')
- elsif planting.before_harvest_time?
%span.badge
= days_from_now_to_first_harvest(planting)
= t('.days_until_harvest')

View File

@@ -1,17 +0,0 @@
- content_for :buttonbar do
- if current_member
= link_to 'My Plantings', plantings_by_owner_path(owner: current_member.slug), class: 'btn btn-default'
- if owner && owner != current_member
= link_to "#{owner.login_name}'s Plantings", plantings_by_owner_path(owner: owner.slug), class: 'btn btn-default'
= link_to "Everyone's plantings", plantings_path, class: 'btn btn-default'
= link_to plantings_active_tickbox_path(@owner, show_all) do
= check_box_tag 'active', 'all', show_all
include in-active
- if current_member
- if can? :create, Planting
= link_to 'Plant something', new_planting_path, class: 'btn btn-primary'
- else
= render partial: 'shared/signin_signup', locals: { to: "track what you've planted" }

View File

@@ -1,13 +1,20 @@
.planting
.planting-badges
= render 'plantings/badges', planting: planting
.hover-wrapper
.thumbnail
.planting-thumbnail{ class: planting_classes(planting) }
= link_to image_tag(planting_image_path(planting),
alt: planting.crop.name, class: 'img'), planting_path(planting)
= render 'plantings/progress', planting: planting, show_explanation: false
.planting-name
= link_to planting.crop.name, planting
.text
.planting-actions= render 'plantings/actions', planting: planting
.planting-quick-actions.pull-right
%a.btn.btn-default.btn-xs#actionsMenu.nav-link.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-toggle" => "dropdown", href: "#"}
=icon('fas', 'bars')
.dropdown-menu{"aria-labelledby" => "actionsMenu"}
%p= render 'plantings/actions', planting: planting
.thumbnail
.planting-thumbnail{ class: planting_classes(planting) }
= link_to image_tag(planting_image_path(planting),
alt: planting.crop.name, class: 'img'), planting_path(planting)
= render 'plantings/progress', planting: planting, show_explanation: false
.planting-name
= link_to planting.crop.name, planting

View File

@@ -1,6 +1,10 @@
- content_for :title, title('plantings', @owner, @crop, @planting)
= render 'nav', owner: @owner, show_all: @show_all
= render 'layouts/nav', model: Planting
= link_to plantings_active_tickbox_path(@owner, @show_all) do
= check_box_tag 'active', 'all', @show_all
include in-active
- if @owner
= link_to t('.view_owners_profile', owner: @owner), member_path(@owner)
@@ -23,4 +27,4 @@
%li= t('.the_data_on_this_page_is_available_in_the_following_formats')
- ['csv', 'json', 'rss'].each do |format|
%li= link_to format.upcase,
(@owner ? plantings_by_owner_path(@owner, format: format) : plantings_path(format: format))
(@owner ? member_plantings_path(@owner, format: format) : plantings_path(format: format))

View File

@@ -1,3 +1,3 @@
= content_for :title, "Plant something"
= content_for :title, t('plantings.plant_something')
= render 'form'

View File

@@ -19,7 +19,7 @@
%dd
= link_to @planting.owner, @planting.owner
&mdash;
= link_to "view all #{@planting.owner}'s plantings", plantings_by_owner_path(owner: @planting.owner.slug)
= link_to "view all #{@planting.owner}'s plantings", member_plantings_path(@planting.owner)
%dt Planted on:
%dd= @planting.planted_at ? @planting.planted_at : "not specified"

View File

@@ -10,7 +10,7 @@
- else # everyone's posts
= link_to 'Post something', new_post_path, class: 'btn btn-primary'
- if current_member
= link_to 'View your posts', posts_by_author_path(author: current_member.slug), class: 'btn btn-default'
= link_to 'View your posts', member_posts_path(current_member), class: 'btn btn-default'
- else
= render partial: 'shared/signin_signup', locals: { to: 'write a post' }
@@ -30,7 +30,7 @@
- if @author
Subscribe to
= succeed "." do
= link_to "#{@author}'s posts RSS feed", posts_by_author_path(format: 'rss', author: @author)
= link_to "#{@author}'s posts RSS feed", member_posts_path(@author, format: 'rss')
- else
Subscribe to the #{ENV['GROWSTUFF_SITE_NAME']}

View File

@@ -1,3 +1,3 @@
= content_for :title, @forum ? "Post in #{@forum.name}" : "Post something"
= content_for :title, @forum ? "Post in #{@forum.name}" : t('posts.write_blog_post')
= render 'form'

View File

@@ -1,8 +1,8 @@
.seed-actions
- if can? :edit, seed
.btn-group
= render 'shared/buttons/edit', path: edit_seed_path(seed)
= render 'shared/buttons/add_photo', path: new_photo_path(id: seed.id, type: 'seed')
= seed_edit_button(seed)
= add_photo_button(seed)
- if can?(:create, Planting) && seed.active?
= link_to new_planting_path(seed_id: seed), class: 'btn btn-default btn-xs' do
@@ -11,5 +11,4 @@
= render 'shared/buttons/finish_seeds', seed: seed
- if can? :destroy, seed
= render 'shared/buttons/delete', path: seed
= delete_button(seed) if can? :destroy, seed

View File

@@ -1,4 +1,5 @@
- content_for :title, title('seeds', @owner, @crop, @planting)
- if @owner
= link_to "View #{@owner}'s profile >>", member_path(@owner)
@@ -6,19 +7,7 @@
#{ENV['GROWSTUFF_SITE_NAME']} helps you track your seed
stash or trade seeds with other members.
%p
- if can? :create, Seed
- if @owner
%p
- if @owner == current_member
= link_to 'Add seeds', new_seed_path, class: 'btn btn-primary'
= link_to "View everyone's seeds", seeds_path, class: 'btn btn-default'
- else # everyone's seeds
= link_to 'Add seeds', new_seed_path, class: 'btn btn-primary'
- if current_member
= link_to 'View your seeds', seeds_by_owner_path(owner: current_member.slug), class: 'btn btn-default'
- else
= render partial: 'shared/signin_signup', locals: { to: 'add seeds to your stash' }
= render 'layouts/nav', model: Seed
.pagination
= page_entries_info @seeds
@@ -37,9 +26,9 @@
%ul.list-inline
%li The data on this page is available in the following formats:
- if @owner
%li= link_to "CSV", seeds_by_owner_path(@owner, format: 'csv')
%li= link_to "JSON", seeds_by_owner_path(@owner, format: 'json')
%li= link_to "RSS", seeds_by_owner_path(@owner, format: 'rss')
%li= link_to "CSV", member_seeds_path(@owner, format: 'csv')
%li= link_to "JSON", member_seeds_path(@owner, format: 'json')
%li= link_to "RSS", member_seeds_path(@owner, format: 'rss')
- else
%li= link_to "CSV", seeds_path(format: 'csv')
%li= link_to "JSON", seeds_path(format: 'json')

View File

@@ -1,3 +1,3 @@
- content_for :title, "Add seeds"
- content_for :title, t('seeds.save_seeds')
= render 'form'

View File

@@ -20,7 +20,7 @@
= link_to @seed.owner, @seed.owner
&mdash;
= link_to "view all #{@seed.owner}'s seeds",
seeds_by_owner_path(owner: @seed.owner.slug)
member_seeds_path(@seed.owner)
%dt Quantity:
%dd= @seed.quantity.blank? ? "not specified" : @seed.quantity
%dt Plant before:

View File

@@ -0,0 +1,22 @@
- if signed_in?
.global-actions.pull-right
.btn-group
= link_to member_gardens_path(current_member), class: 'btn btn-default' do
= garden_icon
= t('links.my_gardens')
.btn-group
= link_to new_planting_path, class: 'btn btn-default' do
= planting_icon
= t('plantings.plant_something')
= link_to new_harvest_path, class: 'btn btn-default' do
= harvest_icon
= t('harvests.harvest_something')
= link_to new_seed_path, class: 'btn btn-default' do
= seed_icon
= t('buttons.save_seeds')
.btn-group
= link_to t('posts.write_blog_post'), new_post_path, class: 'btn btn-default'

View File

@@ -0,0 +1,2 @@
%span.glyphicon{class: "glyphicon-#{icon}", title: t(title) }
=t(title)

View File

@@ -1,4 +0,0 @@
- if can?(:create, Photo)
= link_to path, class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-camera{ title: "Add photo" }
Add photo

View File

@@ -1,4 +1,4 @@
= link_to path, method: :delete,
data: { confirm: 'Are you sure?' }, class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-trash{ title: "Delete" }
Delete
data: { confirm: t(:are_you_sure?) }, class: 'btn btn-default btn-xs' do
= render 'shared/glyphicon', icon: 'trash', title: 'buttons.delete'
=t('buttons.delete')

View File

@@ -1,3 +1,3 @@
= link_to path, class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-pencil{ title: "Edit" }
Edit
= link_to path, class: 'btn btn-default' do
= render 'shared/glyphicon', icon: 'pencil', title: 'buttons.edit'
=t('buttons.edit')

View File

@@ -1,5 +0,0 @@
- if can?(:edit, planting) && !planting.finished
= link_to planting_path(planting, planting: { finished: 1 }),
method: :put, class: 'btn btn-default btn-xs append-date' do
%span.glyphicon.glyphicon-ok{ title: "Finished" }
Mark as finished

View File

@@ -1,5 +1,5 @@
- unless seed.finished
= link_to seed_path(seed, seed: { finished: 1 }),
method: :put, class: 'btn btn-default btn-xs append-date' do
%span.glyphicon.glyphicon-ok{ title: "Finished" }
Mark as finished
= render 'shared/glyphicon', icon: 'ok', title: 'buttons.finished'
=t('buttons.mark_as_finished')

View File

@@ -1,4 +0,0 @@
- planting.active? && if can?(:create, Harvest) && can?(:edit, planting)
= link_to new_planting_harvest_path(planting), class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-leaf{ title: "Harvest" }
Harvest

View File

@@ -1,4 +0,0 @@
- if planting.active?
= link_to new_planting_seed_path(planting), class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-heart{ title: "Save seeds" }
Save seeds

View File

@@ -31,13 +31,6 @@ RAILS_SECRET_TOKEN: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# name that appears on the site, eg. in page titles
GROWSTUFF_SITE_NAME: Growstuff (dev)
# Mandrill is used to send transactional email (eg. signup
# confirmations). If using Heroku connect to Mandrill via Heroku addons
# list then go to tools menu (upper right) and choose "SMTP and API
# Credentials"
GROWSTUFF_MANDRILL_USERNAME: "dummy"
GROWSTUFF_MANDRILL_APIKEY: "dummy"
# Mailchimp is used for subscribing/unsubscribing people from the newsletter
# To fetch list IDs using Gibbon (and thus find the ID of your newsletter):
# $ rails c

View File

@@ -63,13 +63,6 @@ Rails.application.configure do
config.action_mailer.default_url_options = { host: 'localhost:3000' }
config.action_mailer.delivery_method = :letter_opener
config.action_mailer.smtp_settings = {
port: '587',
address: 'smtp.mandrillapp.com',
user_name: ENV['GROWSTUFF_MANDRILL_USERNAME'],
password: ENV['GROWSTUFF_MANDRILL_APIKEY'],
authentication: :login
}
config.host = 'localhost:3000'
config.analytics_code = ''

View File

@@ -63,6 +63,27 @@ en:
seed:
one: seed
other: seeds
application_helper:
title:
title:
default: Default
are_you_sure: Are you sure?
buttons:
add: Add
add_photo: Add photo
add_seed_to_stash: Add %{crop_name} seeds to stash
delete: Delete
edit: Edit
harvest: Harvest
harvest_crop: Harvest %{crop_name}
mark_as_active: Mark as active
mark_as_finished: Mark as finished
mark_as_inactive: Mark as inactive
plant: Plant
plant_crop: Plant %{crop_name}
plant_something_here: Plant something here
save_seeds: Save seeds
write_blog_post: Write blog post
crops:
index:
subtitle: "%{crops_size} total"
@@ -71,6 +92,7 @@ en:
link: You have %{number_crops} crops awaiting approval
subtitle: Pending approval
title: Requested crops
edit_crop: Edit crop
forms:
optional: "(Optional)"
forums:
@@ -82,35 +104,33 @@ en:
form:
location_helper: If you have a location set in your profile, it will be used when you create a new garden.
location: "%{owner}'s %{garden}"
updated: Garden was successfully updated.
overview:
gardensphoto: gardens/photo
plantingsthumbnail: plantings/thumbnail
no_plantings: no plantings
gardensactions: gardens/actions
gardensphoto: gardens/photo
no_plantings: no plantings
plantingsthumbnail: plantings/thumbnail
updated: Garden was successfully updated.
harvests:
created: Harvest was successfully created.
harvest_something: Harvest something
index:
title:
crop_harvests: Everyone's %{crop} harvests
planting_harvests: Harvests from %{planting}
default: Everyone's harvests
owner_harvests: "%{owner} harvests"
planting_harvests: Harvests from %{planting}
updated: Harvest was successfully updated.
home:
blurb:
already_html: Or %{sign_in} if you already have an account
intro: >
%{site_name} is a community of food gardeners. We're building an open source
platform to help you learn about growing food, track what you plant and harvest,
and swap seeds and produce with other gardeners near you.
intro: "%{site_name} is a community of food gardeners. We're building an open source platform to help you learn about growing food, track what you plant and harvest, and swap seeds and produce with other gardeners near you.\n"
perks: Join now for your free garden journal, seed sharing, forums, and more.
sign_in_linktext: sign in
sign_up: Sign up
crops:
our_crops: Some of our crops
recently_added: Recently added crops
recently_planted: Recently planted
recently_planted: Recently Planted
view_all: View all crops
discuss:
discussion: Discussion
@@ -122,6 +142,7 @@ en:
harvest: Harvest
plant: Plant
post: Post
recently_added: Recently Added
welcome: Welcome to %{site_name}, %{member_name}
members:
title: Some of our members
@@ -151,6 +172,8 @@ en:
talk_linktext: Growstuff Talk
why_linktext: why Growstuff is open source
wiki_linktext: Growstuff Wiki
plantings:
recently_planted: Recently Planted
seeds:
crop: Crop
description: Description
@@ -195,7 +218,10 @@ en:
support_growstuff: Support Growstuff
toggle_navigation: Toggle Navigation
your_stuff: Your Stuff (%{unread_count})
links:
my_gardens: My gardens
members:
edit_profile: Edit profile
index:
title: "%{site_name} members"
signup:
@@ -215,6 +241,14 @@ en:
index:
title: "%{site_name} Community Map"
plantings:
badges:
days_until_finished: days until finished
days_until_harvest: days until harvest
harvesting_now: harvesting now
late_finishing: late finishing
sharedbuttonsfinish_planting: shared/buttons/finish_planting
super_late: super late
plant_something: Plant something
form:
finish_helper: >
A planting is finished when you've harvested all of the crop, or it dies, or it's otherwise
@@ -230,13 +264,13 @@ en:
badges:
late_finishing: late finishing
super_late: super late
sharedbuttonsfinish_planting: shared/buttons/finish_planting
days_until_finished: days until finished
harvesting_now: harvesting now
days_until_harvest: days until harvest
progress:
progress_0_not_planted_yet: 'Progress: 0% - not planted yet'
posts:
write_blog_post: Write blog post
index:
title:
author_posts: "%{author} posts"
@@ -252,6 +286,7 @@ en:
crop_seeds: Everyone's %{crop} seeds
default: Everyone's seeds
owner_seeds: "%{owner} seeds"
save_seeds: Save seeds
string: "%{crop} seeds belonging to %{owner}"
unauthorized:
create:

View File

@@ -1,8 +1,6 @@
Rails.application.routes.draw do
get '/robots.txt' => 'robots#robots'
resources :plant_parts
devise_for :members, controllers: {
registrations: "registrations",
passwords: "passwords",
@@ -14,84 +12,105 @@ Rails.application.routes.draw do
end
match '/members/:id/finish_signup' => 'members#finish_signup', via: %i(get patch), as: :finish_signup
resources :members
resources :photos
delete 'photo_associations' => 'photo_associations#destroy'
resources :authentications, only: %i(create destroy)
resources :plantings do
get "home/index"
root to: 'home#index'
concern :has_photos do
resources :photos, only: :index
end
resources :gardens, concerns: :has_photos do
get 'timeline' => 'charts/gardens#timeline', constraints: { format: 'json' }
end
resources :plantings, concerns: :has_photos do
resources :harvests
resources :seeds
collection do
get 'crop/:crop' => 'plantings#index', as: 'plantings_by_crop'
end
end
get '/plantings/owner/:owner' => 'plantings#index', as: 'plantings_by_owner'
get '/plantings/crop/:crop' => 'plantings#index', as: 'plantings_by_crop'
resources :gardens do
get 'timeline' => 'charts/gardens#timeline'
end
get '/gardens/owner/:owner' => 'gardens#index', as: 'gardens_by_owner'
resources :seeds do
resources :seeds, concerns: :has_photos do
resources :plantings
get 'crop/:crop' => 'seeds#index', as: 'seeds_by_crop', on: :collection
end
get '/seeds/owner/:owner' => 'seeds#index', as: 'seeds_by_owner'
get '/seeds/crop/:crop' => 'seeds#index', as: 'seeds_by_crop'
resources :harvests
get '/harvests/owner/:owner' => 'harvests#index', as: 'harvests_by_owner'
get '/harvests/crop/:crop' => 'harvests#index', as: 'harvests_by_crop'
resources :harvests, concerns: :has_photos do
get 'crop/:crop' => 'harvests#index', as: 'harvests_by_crop', on: :collection
end
resources :posts
get '/posts/author/:author' => 'posts#index', as: 'posts_by_author'
resources :posts do
get 'author/:author' => 'posts#index', as: 'by_author', on: :collection
end
resources :scientific_names
resources :alternate_names
resources :plant_parts
resources :photos
get 'crops/requested' => 'crops#requested', as: 'requested_crops'
get 'crops/wrangle' => 'crops#wrangle', as: 'wrangle_crops'
get 'crops/hierarchy' => 'crops#hierarchy', as: 'crops_hierarchy'
get 'crops/search' => 'crops#search', as: 'crops_search'
resources :crops do
get 'photos' => 'photos#index'
get 'sunniness' => 'charts/crops#sunniness'
get 'planted_from' => 'charts/crops#planted_from'
get 'harvested_for' => 'charts/crops#harvested_for'
delete 'photo_associations' => 'photo_associations#destroy'
resources :crops, param: :slug, concerns: :has_photos do
get 'gardens' => 'gardens#index'
get 'harvests' => 'harvests#index'
get 'plantings' => 'plantings#index'
get 'seeds' => 'seeds#index'
get 'places' => 'places#index'
get 'members' => 'members#index'
# Charts json
get 'sunniness' => 'charts/crops#sunniness', constraints: { format: 'json' }
get 'planted_from' => 'charts/crops#planted_from', constraints: { format: 'json' }
get 'harvested_for' => 'charts/crops#harvested_for', constraints: { format: 'json' }
collection do
get 'requested'
get 'wrangle'
get 'hierarchy'
get 'search'
end
end
resources :comments
resources :roles
resources :forums
resources :notifications do
get 'reply', on: :member
end
resources :follows, only: %i(create destroy)
get '/members/:login_name/follows' => 'members#view_follows', as: 'member_follows'
get '/members/:login_name/followers' => 'members#view_followers', as: 'member_followers'
get '/places' => 'places#index'
get '/places/search' => 'places#search', as: 'search_places'
get '/places/:place' => 'places#show', as: 'place'
resources :likes, only: %i(create destroy)
get "home/index"
root to: 'home#index'
resources :members, param: :slug do
resources :gardens
resources :seeds
resources :plantings
resources :harvests
resources :posts
resources :follows
get 'followers' => 'follows#followers'
end
resources :notifications do
get 'reply'
end
resources :places, only: %i(index show), param: :place do
get 'search', on: :collection
end
get 'auth/:provider/callback' => 'authentications#create'
get 'members/auth/:provider/callback' => 'authentications#create'
comfy_route :cms_admin, path: '/admin/cms'
namespace :admin do
resources :members
scope :admin do
resources :members, controller: 'admin/members', as: 'admin_members'
get '/' => 'admin#index', as: 'admin'
get '/newsletter' => 'admin#newsletter', as: 'admin_newsletter'
comfy_route :cms_admin, path: '/cms'
end
get '/admin' => 'admin#index'
get '/admin/newsletter' => 'admin#newsletter', as: :admin_newsletter
get '/admin/:action' => 'admin#:action'
namespace :api do
namespace :v1 do
jsonapi_resources :photos

View File

@@ -4,15 +4,15 @@ describe Charts::CropsController do
describe 'GET charts' do
let(:crop) { FactoryBot.create :crop }
describe 'sunniness' do
before { get :sunniness, params: { crop_id: crop.to_param } }
before { get :sunniness, params: { crop_slug: crop.to_param } }
it { expect(response).to be_success }
end
describe 'planted_from' do
before { get :planted_from, params: { crop_id: crop.to_param } }
before { get :planted_from, params: { crop_slug: crop.to_param } }
it { expect(response).to be_success }
end
describe 'harvested_for' do
before { get :harvested_for, params: { crop_id: crop.to_param } }
before { get :harvested_for, params: { crop_slug: crop.to_param } }
it { expect(response).to be_success }
end
end

View File

@@ -13,26 +13,26 @@ describe HarvestsController do
end
describe "GET index" do
let(:member1) { FactoryBot.create(:member) }
let!(:member1) { FactoryBot.create(:member) }
let(:member2) { FactoryBot.create(:member) }
let(:tomato) { FactoryBot.create(:tomato) }
let(:maize) { FactoryBot.create(:maize) }
let(:harvest1) { FactoryBot.create(:harvest, owner_id: member1.id, crop_id: tomato.id) }
let(:harvest2) { FactoryBot.create(:harvest, owner_id: member2.id, crop_id: maize.id) }
let!(:harvest1) { FactoryBot.create(:harvest, owner_id: member1.id, crop_id: tomato.id) }
let!(:harvest2) { FactoryBot.create(:harvest, owner_id: member2.id, crop_id: maize.id) }
describe "assigns all harvests as @harvests" do
before { get :index, params: {} }
it { assigns(:harvests).should =~ [harvest1, harvest2] }
it { expect(assigns(:harvests)).to eq [harvest1, harvest2] }
end
describe "picks up owner from params and shows owner's harvests only" do
before { get :index, params: { owner: member1.slug } }
before { get :index, params: { member_slug: member1.slug } }
it { expect(assigns(:owner)).to eq member1 }
it { expect(assigns(:harvests)).to eq [harvest1] }
end
describe "picks up crop from params and shows the harvests for the crop only" do
before { get :index, params: { crop: maize.name } }
before { get :index, params: { crop_slug: maize.name } }
it { expect(assigns(:crop)).to eq maize }
it { expect(assigns(:harvests)).to eq [harvest2] }
end
@@ -82,15 +82,15 @@ describe HarvestsController do
end.to change(Harvest, :count).by(1)
end
it "assigns a newly created harvest as @harvest" do
post :create, params: { harvest: valid_attributes }
assigns(:harvest).should be_a(Harvest)
assigns(:harvest).should be_persisted
describe "assigns a newly created harvest as @harvest" do
before { post :create, params: { harvest: valid_attributes } }
it { expect(assigns(:harvest)).to be_a(Harvest) }
it { expect(assigns(:harvest)).to be_persisted }
end
it "redirects to the created harvest" do
post :create, params: { harvest: valid_attributes }
response.should redirect_to(Harvest.last)
describe "redirects to the created harvest" do
before { post :create, params: { harvest: valid_attributes } }
it { expect(response).to redirect_to(Harvest.last) }
end
describe "links to planting" do
@@ -105,13 +105,13 @@ describe HarvestsController do
# Trigger the behavior that occurs when invalid params are submitted
Harvest.any_instance.stub(:save).and_return(false)
post :create, params: { harvest: { "crop_id" => "invalid value" } }
assigns(:harvest).should be_a_new(Harvest)
expect(assigns(:harvest)).to be_a_new(Harvest)
end
it "re-renders the 'new' template" do
describe "re-renders the 'new' template" do
# Trigger the behavior that occurs when invalid params are submitted
post :create, params: { harvest: { "crop_id" => "invalid value" } }
response.should render_template("new")
before { post :create, params: { harvest: { "crop_id" => "invalid value" } } }
it { expect(response).to render_template("new") }
end
end
@@ -132,8 +132,8 @@ describe HarvestsController do
describe "PUT update" do
describe "with valid params" do
let(:harvest) { Harvest.create! valid_attributes }
it "updates the requested harvest" do
harvest = FactoryBot.create :harvest, valid_attributes
new_crop = FactoryBot.create :crop
expect do
put :update, params: { id: harvest.to_param, harvest: { crop_id: new_crop.id } }
@@ -141,16 +141,14 @@ describe HarvestsController do
end.to change(harvest, :crop_id).to(new_crop.id)
end
it "assigns the requested harvest as @harvest" do
harvest = Harvest.create! valid_attributes
put :update, params: { id: harvest.to_param, harvest: valid_attributes }
assigns(:harvest).should eq(harvest)
describe "assigns the requested harvest as @harvest" do
before { put :update, params: { id: harvest.to_param, harvest: valid_attributes } }
it { expect(assigns(:harvest)).to eq(harvest) }
end
it "redirects to the harvest" do
harvest = Harvest.create! valid_attributes
put :update, params: { id: harvest.to_param, harvest: valid_attributes }
response.should redirect_to(harvest)
describe "redirects to the harvest" do
before { put :update, params: { id: harvest.to_param, harvest: valid_attributes } }
it { expect(response).to redirect_to(harvest) }
end
end
@@ -160,13 +158,13 @@ describe HarvestsController do
# Trigger the behavior that occurs when invalid params are submitted
Harvest.any_instance.stub(:save).and_return(false)
put :update, params: { id: harvest.to_param, harvest: { "crop_id" => "invalid value" } }
assigns(:harvest).should eq(harvest)
expect(assigns(:harvest)).to eq(harvest)
end
it "re-renders the 'edit' template" do
harvest = Harvest.create! valid_attributes
put :update, params: { id: harvest.to_param, harvest: { "crop_id" => "invalid value" } }
response.should render_template("edit")
expect(response).to render_template("edit")
end
end
@@ -196,7 +194,7 @@ describe HarvestsController do
it "redirects to the harvests list" do
harvest = Harvest.create! valid_attributes
delete :destroy, params: { id: harvest.to_param }
response.should redirect_to(harvests_url)
expect(response).to redirect_to(harvests_url)
end
end
end

View File

@@ -24,43 +24,43 @@ describe MembersController do
describe "GET show" do
it "provides JSON for member profile" do
get :show, params: { id: @member.id }, format: 'json'
get :show, params: { slug: @member.to_param }, format: 'json'
response.should be_success
end
it "assigns @posts with the member's posts" do
get :show, params: { id: @member.id }
get :show, params: { slug: @member.to_param }
assigns(:posts).should eq(@posts)
end
it "assigns @twitter_auth" do
get :show, params: { id: @member.id }
get :show, params: { slug: @member.to_param }
assigns(:twitter_auth).should eq(@twitter_auth)
end
it "assigns @flickr_auth" do
get :show, params: { id: @member.id }
get :show, params: { slug: @member.to_param }
assigns(:flickr_auth).should eq(@flickr_auth)
end
it "doesn't show completely nonsense members" do
get :show, params: { id: 9999 }
get :show, params: { slug: 9999 }
expect(response).to have_http_status(:not_found)
end
it "doesn't show unconfirmed members" do
@member2 = FactoryBot.create(:unconfirmed_member)
get :show, params: { id: @member2.id }
get :show, params: { slug: @member2.id }
expect(response).to have_http_status(:not_found)
end
end
describe "GET member's RSS feed" do
it "returns an RSS feed" do
get :show, params: { id: @member.to_param }, format: "rss"
response.should be_success
response.should render_template("members/show")
response.content_type.should eq("application/rss+xml")
describe "returns an RSS feed" do
before { get :show, params: { slug: @member.to_param }, format: "rss" }
it { response.should be_success }
it { response.should render_template("members/show") }
it { response.content_type.should eq("application/rss+xml") }
end
end
end

View File

@@ -11,23 +11,6 @@ describe NotificationsController do
}
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" => FactoryBot.create(:member).id,
"subject" => 'test'
}
end
def valid_session
{}
end
describe "GET index" do
it "assigns all notifications as @notifications" do
notification = FactoryBot.create(:notification, recipient_id: subject.current_member.id)
@@ -65,7 +48,7 @@ describe NotificationsController do
describe "GET reply" do
it "marks notifications as read" do
notification = FactoryBot.create(:notification, recipient_id: subject.current_member.id)
get :reply, params: { id: notification.to_param }
get :reply, params: { notification_id: notification.to_param }
# we need to fetch it from the db again, can't test against the old one
n = Notification.find(notification.id)
n.read.should eq true

View File

@@ -25,13 +25,13 @@ describe PlantingsController do
end
describe "picks up owner from params and shows owner's plantings only" do
before { get :index, params: { owner: member1.slug } }
before { get :index, params: { member_slug: member1.slug } }
it { expect(assigns(:owner)).to eq member1 }
it { expect(assigns(:plantings)).to eq [planting1] }
end
describe "picks up crop from params and shows the plantings for the crop only" do
before { get :index, params: { crop: maize.name } }
before { get :index, params: { crop_slug: maize.slug } }
it { expect(assigns(:crop)).to eq maize }
it { expect(assigns(:plantings)).to eq [planting2] }
end

View File

@@ -6,7 +6,7 @@ describe SeedsController do
describe "GET index" do
let(:owner) { FactoryBot.create(:member) }
describe "picks up owner from params" do
before { get :index, params: { owner: owner.slug } }
before { get :index, params: { member_slug: owner.slug } }
it { expect(assigns(:owner)).to eq(owner) }
end
end

View File

@@ -105,13 +105,13 @@ feature "crop detail page", js: true do
background { subject }
scenario "has a link to plant the crop" do
expect(page).to have_link "Plant this", href: new_planting_path(crop_id: crop.id)
expect(page).to have_link "Plant #{crop.name}", href: new_planting_path(crop_id: crop.id)
end
scenario "has a link to harvest the crop" do
expect(page).to have_link "Harvest this", href: new_harvest_path(crop_id: crop.id)
expect(page).to have_link "Harvest #{crop.name}", href: new_harvest_path(crop_id: crop.id)
end
scenario "has a link to add seeds" do
expect(page).to have_link "Add seeds to stash", href: new_seed_path(crop_id: crop.id)
expect(page).to have_link "Add #{crop.name} seeds to stash", href: new_seed_path(crop_id: crop.id)
end
end
@@ -157,23 +157,20 @@ feature "crop detail page", js: true do
scenario "User not signed in" do
visit crop_path(seed.crop)
expect(page).not_to have_content "You have 20 seeds of this crop"
expect(page).not_to have_content "You don't have any seeds of this crop"
expect(page).not_to have_link "View your seeds"
expect(page).not_to have_content "You have 20 seeds"
end
scenario "User signed in" do
login_as(member)
visit crop_path(seed.crop)
expect(page).to have_content "You have 20 seeds of this crop."
expect(page).to have_link "View your seeds"
expect(page).to have_link "You have 20 seeds of this crop."
end
scenario "click link to your owned seeds" do
login_as(member)
visit crop_path(seed.crop)
click_link "View your seeds"
expect(current_path).to eq seeds_by_owner_path(owner: member.slug)
click_link "You have 20 seeds of this crop."
expect(current_path).to eq member_seeds_path(member_slug: member.slug)
end
end

View File

@@ -11,12 +11,12 @@ feature "crop search" do
end
scenario "search page with no search term shows suitable title" do
visit crops_search_path
visit search_crops_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
visit search_crops_path
expect(page).to have_css "form#crop-search"
end
end

View File

@@ -32,11 +32,11 @@ feature "crop wranglers", js: true do
end
end
scenario "visiting a crop can see wrangler links" do
visit crop_path(crops.first)
expect(page).to have_content 'You are a CROP WRANGLER'
expect(page).to have_link 'Edit crop'
expect(page).to have_link 'Delete crop'
describe "visiting a crop can see wrangler links" do
before { visit crop_path(crops.first) }
it { expect(page).to have_content 'You are a CROP WRANGLER' }
it { expect(page).to have_link 'Edit' }
it { expect(page).to have_link 'Delete' }
end
scenario "can create a new crop" do

View File

@@ -26,12 +26,10 @@ feature "follows", :js do
end
context "following another member" do
background do
visit member_path(other_member)
end
background { visit member_path(other_member) }
scenario "has a follow button" do
expect(page).to have_link "Follow", href: follows_path(followed_id: other_member.id)
expect(page).to have_link "Follow", href: follows_path(followed: other_member.slug)
end
scenario "has correct message and unfollow button" do
@@ -43,12 +41,7 @@ feature "follows", :js do
scenario "has a followed member listed in the following page" do
click_link 'Follow'
visit member_follows_path(member)
expect(page).to have_content other_member.login_name.to_s
end
scenario "does not die when passed an authenticity_token" do
visit member_follows_path member, params: { authenticity_token: "Ultima ratio regum" }
expect(page.status_code).to equal 200
expect(page).to have_content other_member.login_name
end
scenario "has correct message and follow button after unfollow" do
@@ -56,28 +49,28 @@ feature "follows", :js do
click_link 'Unfollow'
expect(page).to have_content "Unfollowed #{other_member.login_name}"
visit member_path(other_member) # unfollowing redirects to root
expect(page).to have_link "Follow", href: follows_path(followed_id: other_member.id)
expect(page).to have_link "Follow", href: follows_path(followed: other_member.slug)
end
scenario "has member in following list" do
click_link 'Follow'
visit member_follows_path(member)
expect(page).to have_content other_member.login_name.to_s
expect(page).to have_content other_member.login_name
end
scenario "appears in in followed member's followers list" do
click_link 'Follow'
visit member_followers_path(other_member)
expect(page).to have_content member.login_name.to_s
expect(page).to have_content member.login_name
end
scenario "removes members from following and followers lists after unfollow" do
click_link 'Follow'
click_link 'Unfollow'
visit member_follows_path(member)
expect(page).not_to have_content other_member.login_name.to_s
expect(page).not_to have_content other_member.login_name
visit member_followers_path(other_member)
expect(page).to have_content member.login_name.to_s
expect(page).to have_content member.login_name
end
end
end

View File

@@ -9,30 +9,29 @@ feature "Gardens" do
background { login_as member }
let(:garden) { member.gardens.first }
let(:other_member_garden) { FactoryBot.create :garden }
describe '#index' do
shared_examples "has buttons bar at top" do
it "has buttons bar at top" do
within '.layout-actions' do
is_expected.to have_link 'Add a garden'
is_expected.to have_link 'My Gardens'
is_expected.to have_link 'My gardens'
is_expected.to have_link "Everyone's gardens"
end
end
end
context 'my gardens' do
before { visit gardens_path(owner: member) }
before { visit gardens_path(member_slug: member.slug) }
include_examples "has buttons bar at top"
it "has actions on garden" do
within '.garden-actions' do
is_expected.to have_link 'Plant something'
is_expected.to have_link 'Mark as inactive'
is_expected.to have_link 'Edit'
is_expected.to have_link 'Add photo'
is_expected.to have_link 'Delete'
end
is_expected.to have_link 'Plant something here'
is_expected.to have_link 'Mark as inactive'
is_expected.to have_link 'Edit'
is_expected.to have_link 'Add photo'
is_expected.to have_link 'Delete'
end
end
@@ -43,17 +42,31 @@ feature "Gardens" do
end
context "other member's garden" do
before { visit gardens_path(owner: FactoryBot.create(:member)) }
before { visit gardens_path(member_slug: FactoryBot.create(:member).slug) }
include_examples "has buttons bar at top"
it 'does not show actions on other member garden' do
is_expected.not_to have_link 'Plant something'
is_expected.not_to have_link 'Mark as inactive'
describe 'does not show actions on other member garden' do
it { is_expected.not_to have_link 'Edit' }
it { is_expected.not_to have_link 'Delete' }
end
end
end
describe '#show' do
describe 'my garden' do
before { visit garden_path(garden) }
it { is_expected.to have_link 'Edit' }
it { is_expected.to have_link 'Delete' }
it { is_expected.to have_content "Plant something here" }
it { is_expected.to have_content "Add photo" }
end
describe "someone else's garden" do
before { visit garden_path(other_member_garden) }
it { is_expected.not_to have_link 'Edit' }
it { is_expected.not_to have_link 'Delete' }
it { is_expected.not_to have_content "Plant something here" }
it { is_expected.not_to have_content "Add photo" }
end
end
end

View File

@@ -10,7 +10,7 @@ feature "Gardens#index", :js do
context "with 10 gardens" do
before do
FactoryBot.create_list :garden, 10, owner: member
visit gardens_path(owner: member.login_name)
visit member_gardens_path(member_slug: member.slug)
end
it "displays each of the gardens" do
@@ -29,7 +29,7 @@ feature "Gardens#index", :js do
let!(:active_garden) { FactoryBot.create :garden, name: "My active garden", owner: member }
let!(:inactive_garden) { FactoryBot.create :inactive_garden, name: "retired garden", owner: member }
before { visit gardens_path(member: member) }
before { visit member_gardens_path(member_slug: member.slug) }
it "show active garden" do
expect(page).to have_text active_garden.name
@@ -57,7 +57,7 @@ feature "Gardens#index", :js do
end
before do
visit gardens_path(member: member)
visit member_gardens_path(member_slug: member.slug)
end
it "shows planting in garden" do
@@ -90,7 +90,7 @@ feature "Gardens#index", :js do
garden.update! name: 'super awesome garden'
assert planting
visit gardens_path(owner: member.login_name)
visit member_gardens_path(member_slug: member.slug)
end
describe 'harvest still growing' do

View File

@@ -14,9 +14,13 @@ feature "Planting a crop", js: true do
scenario "View gardens" do
visit gardens_path
expect(page).to have_content "Everyone's gardens"
click_link "My Gardens"
within '.layout-actions' do
click_link "My gardens"
end
expect(page).to have_content "#{garden.owner.login_name}'s gardens"
click_link "Everyone's gardens"
within '.layout-actions' do
click_link "Everyone's gardens"
end
expect(page).to have_content "Everyone's gardens"
end
@@ -82,7 +86,7 @@ feature "Planting a crop", js: true do
fill_in "Name", with: "New garden"
click_button "Save"
visit garden_path(Garden.last)
click_link 'delete_garden_link'
click_link 'Delete'
expect(page).to have_content "Garden was successfully deleted"
expect(page).to have_content "#{garden.owner}'s gardens"
end

View File

@@ -57,14 +57,16 @@ feature "Harvesting a crop", :js, :elasticsearch do
end
scenario "Clicking link to owner's profile" do
visit harvests_by_owner_path(member)
visit member_harvests_path(member)
click_link "View #{member}'s profile >>"
expect(current_path).to eq member_path member
end
scenario "Harvesting from crop page" do
visit crop_path(maize)
click_link "Harvest this"
within '.crop-actions' do
click_link "Harvest #{maize.name}"
end
within "form#new_harvest" do
select plant_part.name, from: 'harvest[plant_part_id]'
expect(page).to have_selector "input[value='maize']"

View File

@@ -84,5 +84,10 @@ feature "home page" do
include_examples 'show plantings'
include_examples 'show harvests'
include_examples 'shows seeds'
describe 'should say welcome' do
before { visit root_path }
it { expect(page).to have_content "Welcome to #{ENV['GROWSTUFF_SITE_NAME']}, #{member.login_name}" }
end
end
end

View File

@@ -81,10 +81,10 @@ feature "member profile", js: true do
create_list :seed, 4, owner: member
create_list :post, 5, author: member
visit member_path(member)
expect(page).to have_link "2 plantings", href: plantings_by_owner_path(owner: member)
expect(page).to have_link "3 harvests", href: harvests_by_owner_path(owner: member)
expect(page).to have_link "4 seeds", href: seeds_by_owner_path(owner: member)
expect(page).to have_link "5 posts", href: posts_by_author_path(author: member)
expect(page).to have_link "2 plantings", href: member_plantings_path(member)
expect(page).to have_link "3 harvests", href: member_harvests_path(member)
expect(page).to have_link "4 seeds", href: member_seeds_path(member)
expect(page).to have_link "5 posts", href: member_posts_path(member)
end
end

View File

@@ -13,7 +13,9 @@ feature "new photo page" do
scenario "add photo" do
visit planting_path(planting)
click_link('Add photo', match: :first)
within '.planting-actions' do
click_link('Add photo')
end
expect(page).to have_text planting.crop.name
end
end
@@ -23,7 +25,9 @@ feature "new photo page" do
scenario "add photo" do
visit harvest_path(harvest)
click_link "Add photo"
within '.harvest-actions' do
click_link "Add photo"
end
expect(page).to have_text harvest.crop.name
end
end

View File

@@ -21,15 +21,15 @@ feature "Planting a crop", :js, :elasticsearch do
expect(page).to have_content "* denotes a required field"
end
it "displays required and optional fields properly" do
expect(page).to have_selector ".form-group.required", text: "What did you plant?"
expect(page).to have_selector ".form-group.required", text: "Where did you plant it?"
expect(page).to have_optional 'input#planting_planted_at'
expect(page).to have_optional 'input#planting_quantity'
expect(page).to have_optional 'select#planting_planted_from'
expect(page).to have_optional 'select#planting_sunniness'
expect(page).to have_optional 'textarea#planting_description'
expect(page).to have_optional 'input#planting_finished_at'
describe "displays required and optional fields properly" do
it { expect(page).to have_selector ".form-group.required", text: "What did you plant?" }
it { expect(page).to have_selector ".form-group.required", text: "Where did you plant it?" }
it { expect(page).to have_optional 'input#planting_planted_at' }
it { expect(page).to have_optional 'input#planting_quantity' }
it { expect(page).to have_optional 'select#planting_planted_from' }
it { expect(page).to have_optional 'select#planting_sunniness' }
it { expect(page).to have_optional 'textarea#planting_description' }
it { expect(page).to have_optional 'input#planting_finished_at' }
end
scenario "Creating a new planting" do
@@ -49,7 +49,7 @@ feature "Planting a crop", :js, :elasticsearch do
end
scenario "Clicking link to owner's profile" do
visit plantings_by_owner_path(member)
visit member_plantings_path(member)
click_link "View #{member}'s profile >>"
expect(current_path).to eq member_path(member)
end
@@ -152,7 +152,9 @@ feature "Planting a crop", :js, :elasticsearch do
scenario "Planting from crop page" do
visit crop_path(maize)
click_link "Plant this"
within '.crop-actions' do
click_link "Plant maize"
end
within "form#new_planting" do
expect(page).to have_selector "input[value='maize']"
click_button "Save"

View File

@@ -59,7 +59,7 @@ feature "Seeds", :js, :elasticsearch do
describe "Adding a seed from crop page" do
before do
visit crop_path(maize)
click_link "Add seeds to stash"
click_link "Add maize seeds to stash"
within "form#new_seed" do
expect(page).to have_selector "input[value='maize']"
click_button "Save"

View File

@@ -21,15 +21,15 @@ feature "seeds", js: true do
describe "button on front page to add seeds" do
before do
visit root_path
click_link "Add seeds"
click_link "Save seeds"
end
it { expect(current_path).to eq new_seed_path }
it { expect(page).to have_content 'Add seeds' }
it { expect(page).to have_content 'Save seeds' }
end
describe "Clicking link to owner's profile" do
before do
visit seeds_by_owner_path(member)
visit member_seeds_path(member)
click_link "View #{member}'s profile >>"
end
it { expect(current_path).to eq member_path(member) }

Some files were not shown because too many files have changed in this diff Show More