Merge remote-tracking branch 'upstream/dev' into upgrade/rails-5

Conflicts:
	.rubocop_todo.yml
	Gemfile.lock
	app/assets/javascripts/application.js
	app/assets/javascripts/members.js.erb
	app/assets/stylesheets/predictions.sass
	app/controllers/crops_controller.rb
	app/controllers/orders_controller.rb
	app/controllers/plantings_controller.rb
	app/models/account.rb
	app/models/account_type.rb
	app/models/member.rb
	app/models/order.rb
	app/models/order_item.rb
	app/models/product.rb
	app/views/gardens/show.html.haml
	app/views/layouts/application.html.haml
	config/initializers/assets.rb
	config/routes.rb
	db/schema.rb
	package-lock.json
	spec/controllers/account_types_controller_spec.rb
	spec/controllers/admin/orders_controller_spec.rb
	spec/controllers/comments_controller_spec.rb
	spec/controllers/gardens_controller_spec.rb
	spec/controllers/harvests_controller_spec.rb
	spec/controllers/member_controller_spec.rb
	spec/controllers/order_items_controller_spec.rb
	spec/controllers/orders_controller_spec.rb
	spec/controllers/photo_associations_controller_spec.rb
	spec/controllers/photos_controller_spec.rb
	spec/controllers/plantings_controller_spec.rb
	spec/controllers/seeds_controller_spec.rb
	spec/controllers/shop_controller_spec.rb
	spec/features/crops/crop_detail_page_spec.rb
	spec/models/member_spec.rb
	spec/models/post_spec.rb
	spec/views/crops/_planting_advice.html.haml_spec.rb
	spec/views/home/_crops.html.haml_spec.rb
	spec/views/orders/show.html.haml_spec.rb
	spec/views/posts/show.html.haml_spec.rb
	spec/views/shop/index_spec.rb
This commit is contained in:
Brenda Wallace
2018-04-02 10:59:13 +12:00
227 changed files with 1328 additions and 4462 deletions

1
.esignore Normal file
View File

@@ -0,0 +1 @@
app/assets/javascripts/bootstrap-accessibility.min.js

View File

@@ -8,3 +8,6 @@ scss:
config_file: .scss-lint.yml
eslint:
config_file: .eslintrc
ignore_file: .esignore
jshint:
enabled: false

View File

@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config --no-offense-counts`
# on 2018-01-11 09:25:35 +1300 using RuboCop version 0.49.1.
# on 2018-02-05 14:37:22 +1300 using RuboCop version 0.49.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
@@ -44,7 +44,6 @@ Rails/SkipsModelValidations:
# SupportedStyles: strict, flexible
Rails/TimeZone:
Exclude:
- 'spec/controllers/accounts_controller_spec.rb'
- 'spec/factories/member.rb'
- 'spec/factories/post.rb'
- 'spec/models/post_spec.rb'
@@ -68,24 +67,11 @@ Style/IdenticalConditionalBranches:
Exclude:
- 'app/controllers/follows_controller.rb'
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: line_count_dependent, lambda, literal
Style/Lambda:
Exclude:
- 'spec/controllers/member_controller_spec.rb'
- 'spec/models/photo_spec.rb'
# Cop supports --auto-correct.
Style/MultilineIfModifier:
Exclude:
- 'spec/rails_helper.rb'
# Cop supports --auto-correct.
Style/MutableConstant:
Exclude:
- 'app/models/planting.rb'
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles.
# SupportedStyles: predicate, comparison
@@ -96,11 +82,6 @@ Style/NumericPredicate:
- 'app/helpers/plantings_helper.rb'
- 'lib/tasks/growstuff.rake'
# Cop supports --auto-correct.
Style/ParallelAssignment:
Exclude:
- 'app/mailers/notifier.rb'
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
# SupportedStyles: slashes, percent_r, mixed

View File

@@ -45,7 +45,6 @@ script:
else
bundle exec rake db:migrate --trace;
bundle exec rspec --tag $RSPEC_TAG spec/;
bundle exec rake jasmine:ci;
fi;
- set +e
before_deploy:

View File

@@ -82,6 +82,7 @@ submit the change with your pull request.
- Harry Brodsky / [hbrodsk1](https://github.com/hbrodsk1)
- Jeff Kingswood / [ancyentmariner](https://github.com/ancyentmariner)
- Logan Gingerich / [logangingerich](https://github.com/logangingerich)
- Mark Taffman / [mftaff](https://github.com/mftaff)
## Bots

View File

@@ -38,7 +38,7 @@ gem 'gibbon', '~>1.2.0' # for Mailchimp newsletter subscriptions
gem 'leaflet-rails'
gem 'rails-assets-leaflet.markercluster', source: 'https://rails-assets.org'
gem 'pg'
gem 'pg', '< 1.0.0' # Upstream bug, see https://github.com/Growstuff/growstuff/pull/1539
gem 'ruby-units' # for unit conversion
gem 'unicorn' # http server
@@ -48,7 +48,6 @@ gem 'bootstrap-kaminari-views' # bootstrap views for kaminari
gem 'kaminari' # pagination
gem 'active_utils'
gem 'activemerchant'
gem 'sidekiq'
# Markdown formatting for updates etc
@@ -123,7 +122,6 @@ group :development do
end
group :development, :test do
gem "active_merchant-paypal-bogus-gateway"
gem 'bullet' # performance tuning by finding unnecesary queries
gem 'byebug' # debugging
gem 'capybara' # integration tests
@@ -137,7 +135,6 @@ group :development, :test do
gem 'haml-rails' # HTML templating language
gem 'haml_lint' # Checks haml files for goodness
gem 'i18n-tasks' # adds tests for finding missing and unused translations
gem 'jasmine' # javascript unit testing
gem 'poltergeist' # for headless JS testing
gem 'rainbow', '< 2.2.0' # See https://github.com/sickill/rainbow/issues/44
gem 'rspec-activemodel-mocks'
@@ -156,3 +153,5 @@ end
group :travis do
gem 'platform-api'
end
gem 'loofah', '>= 2.2.1'
gem 'rack-protection', '>= 2.0.1'

View File

@@ -27,19 +27,12 @@ GEM
rails-html-sanitizer (~> 1.0, >= 1.0.3)
active_median (0.1.4)
activerecord
active_merchant-paypal-bogus-gateway (0.1.0)
activemerchant
active_utils (3.3.9)
activesupport (>= 3.2, < 5.2.0)
active_utils (3.3.11)
activesupport (>= 3.2, < 6.0)
i18n
activejob (5.1.4)
activesupport (= 5.1.4)
globalid (>= 0.3.6)
activemerchant (1.76.0)
activesupport (>= 3.2.14, < 6.x)
builder (>= 2.1.2, < 4.0.0)
i18n (>= 0.6.9)
nokogiri (~> 1.4)
activemodel (5.1.4)
activesupport (= 5.1.4)
activerecord (5.1.4)
@@ -54,8 +47,8 @@ GEM
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
arel (8.0.0)
ast (2.3.0)
autoprefixer-rails (7.2.4)
ast (2.4.0)
autoprefixer-rails (8.2.0)
execjs
bcrypt (3.1.11)
better_errors (2.4.0)
@@ -64,7 +57,7 @@ GEM
rack (>= 0.9.0)
bluecloth (2.2.0)
bonsai-elasticsearch-rails (0.0.4)
bootstrap-datepicker-rails (1.7.1.1)
bootstrap-datepicker-rails (1.8.0.1)
railties (>= 3.0)
bootstrap-kaminari-views (0.0.5)
kaminari (>= 0.13)
@@ -73,12 +66,12 @@ GEM
autoprefixer-rails (>= 5.2.1)
sass (>= 3.3.4)
builder (3.2.3)
bullet (5.7.0)
bullet (5.7.5)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.10.0)
byebug (9.1.0)
cancancan (2.1.2)
capybara (2.17.0)
uniform_notifier (~> 1.11.0)
byebug (10.0.2)
cancancan (2.1.3)
capybara (2.18.0)
addressable
mini_mime (>= 0.1.3)
nokogiri (>= 1.3.3)
@@ -91,8 +84,8 @@ GEM
capybara-screenshot (1.0.18)
capybara (>= 1.0, < 3)
launchy
chartkick (2.2.5)
childprocess (0.8.0)
chartkick (2.3.3)
childprocess (0.9.0)
ffi (~> 1.0, >= 1.0.11)
cliver (0.3.2)
codeclimate-test-reporter (1.0.8)
@@ -116,18 +109,17 @@ GEM
crass (1.0.3)
csv_shaper (1.3.0)
activesupport (>= 3.0.0)
dalli (2.7.6)
dalli (2.7.7)
database_cleaner (1.6.2)
devise (4.4.0)
devise (4.4.3)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0, < 5.2)
railties (>= 4.1.0, < 6.0)
responders
warden (~> 1.2.3)
diff-lcs (1.3)
docile (1.1.5)
easy_translate (0.5.0)
json
easy_translate (0.5.1)
thread
thread_safe
elasticsearch (5.0.4)
@@ -143,9 +135,9 @@ GEM
elasticsearch-transport (5.0.4)
faraday
multi_json
erubi (1.7.0)
erubi (1.7.1)
erubis (2.7.0)
excon (0.60.0)
excon (0.62.0)
execjs (2.7.0)
factory_bot (4.8.2)
activesupport (>= 3.0.0)
@@ -156,15 +148,15 @@ GEM
i18n (>= 0.7)
faraday (0.12.2)
multipart-post (>= 1.2, < 3)
ffi (1.9.18)
ffi (1.9.23)
figaro (1.1.1)
thor (~> 0.14)
flickraw (0.9.9)
font-awesome-sass (4.7.0)
font-awesome-sass (5.0.9)
sass (>= 3.2)
friendly_id (5.2.3)
activerecord (>= 4.0.0)
geocoder (1.4.5)
geocoder (1.4.7)
gibbon (1.2.1)
httparty
multi_json (>= 1.9.0)
@@ -206,9 +198,9 @@ GEM
haml (>= 4.0, < 6)
nokogiri (>= 1.6.0)
ruby_parser (~> 3.5)
httparty (0.15.6)
httparty (0.16.2)
multi_xml (>= 0.5.2)
i18n (0.9.1)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
i18n-tasks (0.9.12)
activesupport (>= 4.0.2)
@@ -220,12 +212,6 @@ GEM
parser (>= 2.2.3.0)
term-ansicolor (>= 1.3.2)
terminal-table (>= 1.5.1)
jasmine (2.8.0)
jasmine-core (>= 2.8.0, < 3.0.0)
phantomjs
rack (>= 1.2.1)
rake
jasmine-core (2.8.0)
jquery-rails (4.3.1)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
@@ -253,18 +239,18 @@ GEM
activerecord
kaminari-core (= 1.1.1)
kaminari-core (1.1.1)
kgio (2.11.1)
kgio (2.11.2)
launchy (2.4.3)
addressable (~> 2.3)
leaflet-rails (1.2.0)
leaflet-rails (1.3.1)
rails (>= 4.2.0)
letter_opener (1.5.0)
letter_opener (1.6.0)
launchy (~> 2.2)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2)
loofah (2.1.1)
loofah (2.2.2)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.0)
@@ -273,14 +259,14 @@ GEM
method_source (0.9.0)
mini_mime (1.0.0)
mini_portile2 (2.3.0)
minitest (5.11.1)
minitest (5.11.3)
moneta (0.8.1)
multi_json (1.11.3)
multi_xml (0.6.0)
multipart-post (2.0.0)
newrelic_rpm (4.7.1.340)
nio4r (2.2.0)
nokogiri (1.8.1)
newrelic_rpm (5.0.0.342)
nio4r (2.3.0)
nokogiri (1.8.2)
mini_portile2 (~> 2.3.0)
oauth (0.5.4)
oauth2 (1.4.0)
@@ -310,10 +296,9 @@ GEM
parallel (1.12.1)
paranoia (2.4.0)
activerecord (>= 4.0, < 5.2)
parser (2.4.0.2)
ast (~> 2.3)
parser (2.5.0.5)
ast (~> 2.4.0)
pg (0.21.0)
phantomjs (2.1.1.0)
platform-api (2.1.0)
heroics (~> 0.0.23)
moneta (~> 0.8.1)
@@ -322,11 +307,11 @@ GEM
cliver (~> 0.3.1)
websocket-driver (>= 0.2.0)
powerpack (0.1.1)
public_suffix (3.0.1)
rack (2.0.3)
rack-protection (2.0.0)
public_suffix (3.0.2)
rack (2.0.4)
rack-protection (2.0.1)
rack
rack-test (0.8.2)
rack-test (1.0.0)
rack (>= 1.0, < 3)
rails (5.1.4)
actioncable (= 5.1.4)
@@ -340,8 +325,8 @@ GEM
bundler (>= 1.3.0)
railties (= 5.1.4)
sprockets-rails (>= 2.0.0)
rails-assets-leaflet (1.2.0)
rails-assets-leaflet.markercluster (1.2.0)
rails-assets-leaflet (1.3.1)
rails-assets-leaflet.markercluster (1.3.0)
rails-assets-leaflet (>= 1.0.3)
rails-controller-testing (1.0.2)
actionpack (~> 5.x, >= 5.0.1)
@@ -350,8 +335,8 @@ GEM
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
rails-html-sanitizer (1.0.4)
loofah (~> 2.2, >= 2.2.2)
rails_12factor (0.0.3)
rails_serve_static_assets
rails_stdout_logging
@@ -365,8 +350,8 @@ GEM
thor (>= 0.18.1, < 2.0)
rainbow (2.1.0)
raindrops (0.19.0)
rake (12.3.0)
rb-fsevent (0.10.2)
rake (12.3.1)
rb-fsevent (0.10.3)
rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2)
redis (4.0.1)
@@ -393,7 +378,7 @@ GEM
rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.7.0)
rspec-support (~> 3.7.0)
rspec-support (3.7.0)
rspec-support (3.7.1)
rubocop (0.49.1)
parallel (~> 1.10)
parser (>= 2.3.3.1, < 3.0)
@@ -402,12 +387,12 @@ GEM
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-progressbar (1.9.0)
ruby-units (2.2.1)
ruby-units (2.3.0)
ruby_dep (1.5.0)
ruby_parser (3.10.1)
ruby_parser (3.11.0)
sexp_processor (~> 4.9)
rubyzip (1.2.1)
sass (3.5.4)
sass (3.5.6)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
@@ -418,15 +403,15 @@ GEM
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
selenium-webdriver (3.8.0)
selenium-webdriver (3.11.0)
childprocess (~> 0.5)
rubyzip (~> 1.0)
sexp_processor (4.10.0)
sidekiq (5.0.5)
rubyzip (~> 1.2)
sexp_processor (4.10.1)
sidekiq (5.1.2)
concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0)
rack-protection (>= 1.5.0)
redis (>= 3.3.4, < 5)
redis (>= 3.3.5, < 5)
simplecov (0.12.0)
docile (~> 1.1.0)
json (>= 1.8, < 3)
@@ -454,15 +439,15 @@ GEM
timecop (0.9.1)
tins (1.16.3)
trollop (1.16.2)
tzinfo (1.2.4)
tzinfo (1.2.5)
thread_safe (~> 0.1)
uglifier (4.1.2)
uglifier (4.1.8)
execjs (>= 0.3.0, < 3)
unicode-display_width (1.3.0)
unicorn (5.4.0)
kgio (~> 2.6)
raindrops (~> 0.7)
uniform_notifier (1.10.0)
uniform_notifier (1.11.0)
warden (1.2.7)
rack (>= 1.0)
webrat (0.7.3)
@@ -482,9 +467,7 @@ PLATFORMS
DEPENDENCIES
active_median
active_merchant-paypal-bogus-gateway
active_utils
activemerchant
better_errors
bluecloth
bonsai-elasticsearch-rails
@@ -524,7 +507,6 @@ DEPENDENCIES
haml_lint
hashie (>= 3.5.3)
i18n-tasks
jasmine
jquery-rails
jquery-ui-rails
js-routes
@@ -533,6 +515,7 @@ DEPENDENCIES
leaflet-rails
letter_opener
listen
loofah (>= 2.2.1)
memcachier
newrelic_rpm
omniauth (~> 1.3)
@@ -540,9 +523,10 @@ DEPENDENCIES
omniauth-flickr (>= 0.0.15)
omniauth-twitter
paranoia (~> 2.2)
pg
pg (< 1.0.0)
platform-api
poltergeist
rack-protection (>= 2.0.1)
rails (= 5.1.4)
rails-assets-leaflet.markercluster!
rails-controller-testing

View File

@@ -10,8 +10,6 @@
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
//
// = require Chart.bundle
// = require chartkick
// = require leaflet
// = require leaflet.markercluster
// = require js-routes

View File

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
// = require Chart.bundle
// = require chartkick

View File

@@ -0,0 +1,39 @@
jQuery ->
$('#add-sci_name-row').css("display", "inline-block")
$('#remove-sci_name-row').css("display", "inline-block")
$("#add-alt_name-row").css("display", "inline-block")
$("#remove-alt_name-row").css("display", "inline-block")
-$ ->
sci_template = "<div id='sci_template[INDEX]' class='template col-md-12'><div class='col-md-2'><label>Scientific name INDEX:</label></div><div class='col-md-8'><input name='sci_name[INDEX]' class='form-control', id='sci_name[INDEX]')'></input><span class='help-block'>Scientific name of crop.</span></div><div class='col-md-2'></div></div>"
sci_index = $('#scientific_names .template').length + 1
$('#add-sci_name-row').click ->
compiled_input = $(sci_template.split("INDEX").join(sci_index))
$('#scientific_names').append(compiled_input)
sci_index = sci_index + 1
$('#remove-sci_name-row').click ->
if (sci_index > 2)
sci_index = sci_index - 1
tmp = 'sci_template[' + sci_index + ']'
element = document.getElementById(tmp)
element.remove()
alt_template = "<div id='alt_template[INDEX]' class='template col-md-12'><div class='col-md-2'><label>Alternate name INDEX:</label></div><div class='col-md-8'><input name='alt_name[INDEX]' class='form-control', id='alt_name[INDEX]')'></input><span class='help-block'>Alternate name of crop.</span></div><div class='col-md-2'></div></div>"
alt_index = $('#alternate_names .template').length + 1
$('#add-alt_name-row').click ->
compiled_input = $(alt_template.split("INDEX").join(alt_index))
$('#alternate_names').append(compiled_input)
alt_index = alt_index + 1
$('#remove-alt_name-row').click ->
if (alt_index > 2)
alt_index = alt_index - 1
tmp = 'alt_template[' + alt_index + ']'
element = document.getElementById(tmp)
console.log("%s",tmp)
element.remove()

View File

@@ -0,0 +1,19 @@
# Clears the finished at date field when
# a seed is marked unfinished, and
# repopulates the field with a cached value
# marking unfinished is undone.
jQuery ->
previousValue = ''
$('#seed_finished').on('click', ->
finished = $('#seed_finished_at')
if @checked
if previousValue.length
date = previousValue
finished.val(date)
else
finished.trigger('focus')
else
previousValue = finished.val()
finished.val('')
)

View File

@@ -4,41 +4,3 @@
jQuery ->
$('.add-datepicker').datepicker('format' : 'yyyy-mm-dd')
$('#add-sci_name-row').css("display", "inline-block")
$('#remove-sci_name-row').css("display", "inline-block")
$("#add-alt_name-row").css("display", "inline-block")
$("#remove-alt_name-row").css("display", "inline-block")
$ ->
sci_template = "<div id='sci_template[INDEX]' class='template col-md-12'><div class='col-md-2'><label>Scientific name INDEX:</label></div><div class='col-md-8'><input name='sci_name[INDEX]' class='form-control', id='sci_name[INDEX]')'></input><span class='help-block'>Scientific name of crop.</span></div><div class='col-md-2'></div></div>"
sci_index = $('#scientific_names .template').length + 1
$('#add-sci_name-row').click ->
compiled_input = $(sci_template.split("INDEX").join(sci_index))
$('#scientific_names').append(compiled_input)
sci_index = sci_index + 1
$('#remove-sci_name-row').click ->
if (sci_index > 2)
sci_index = sci_index - 1
tmp = 'sci_template[' + sci_index + ']'
element = document.getElementById(tmp)
element.remove()
alt_template = "<div id='alt_template[INDEX]' class='template col-md-12'><div class='col-md-2'><label>Alternate name INDEX:</label></div><div class='col-md-8'><input name='alt_name[INDEX]' class='form-control', id='alt_name[INDEX]')'></input><span class='help-block'>Alternate name of crop.</span></div><div class='col-md-2'></div></div>"
alt_index = $('#alternate_names .template').length + 1
$('#add-alt_name-row').click ->
compiled_input = $(alt_template.split("INDEX").join(alt_index))
$('#alternate_names').append(compiled_input)
alt_index = alt_index + 1
$('#remove-alt_name-row').click ->
if (alt_index > 2)
alt_index = alt_index - 1
tmp = 'alt_template[' + alt_index + ']'
element = document.getElementById(tmp)
console.log("%s",tmp)
element.remove()

View File

@@ -1 +1 @@
.btn:focus{outline:dotted 2px #000}div.active:focus{outline:dotted 1px #000}a:focus{outline:dotted 1px #000}.close:hover,.close:focus{outline:dotted 1px #000}.nav>li>a:hover,.nav>li>a:focus{outline:dotted 1px #000}.carousel-inner>.item{position:absolute;top:-999999em;display:block;-moz-transition:ease-in-out 0.6s left;-o-transition:ease-in-out 0.6s left;-webkit-transition:ease-in-out 0.6s left;transition:ease-in-out 0.6s left}.carousel-inner>.active{top:0}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{position:relative}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.alert-success{color:#2d4821}.alert-info{color:#214c62}.alert-warning{color:#6c4a00;background-color:#f9f1c6}.alert-danger{color:#d2322d}.alert-danger:hover{color:#a82824}
.btn:focus{outline:dotted 2px #000}div.active:focus{outline:dotted 1px #000}a:focus{outline:dotted 1px #000}.close:hover,.close:focus{outline:dotted 1px #000}.nav>li>a:hover,.nav>li>a:focus{outline:dotted 1px #000}.carousel-indicators li,.carousel-indicators li.active{height:18px;width:18px;border-width:2px;position:relative;box-shadow:0px 0px 0px 1px #808080}.carousel-indicators.active li{background-color:rgba(100,149,253,0.6)}.carousel-indicators.active li.active{background-color:white}.carousel-tablist-highlight{display:block;position:absolute;outline:2px solid transparent;background-color:transparent;box-shadow:0px 0px 0px 1px transparent}.carousel-tablist-highlight.focus{outline:2px solid #6495ED;background-color:rgba(0,0,0,0.4)}a.carousel-control:focus{outline:2px solid #6495ED;background-image:linear-gradient(to right, transparent 0px, rgba(0,0,0,0.5) 100%);box-shadow:0px 0px 0px 1px #000000}.carousel-pause-button{position:absolute;top:-30em;left:-300em;display:block}.carousel-pause-button.focus{top:0.5em;left:0.5em}.carousel:hover .carousel-caption,.carousel.contrast .carousel-caption{background-color:rgba(0,0,0,0.5);z-index:10}.alert-success{color:#2d4821}.alert-info{color:#214c62}.alert-warning{color:#6c4a00;background-color:#f9f1c6}.alert-danger{color:#d2322d}.alert-danger:hover{color:#a82824}

View File

@@ -94,21 +94,6 @@ p.stats
dd
margin-left: auto
@media (min-width: $screen-md-min)
.planting-thumbnail
dl.planting-attributes
width: 100%
dt
text-align: left
width: 120px
dd
padding-left: 120px
margin-left: auto
.navbar .navbar-form
width: 250px
#placesmap, #cropmap
height: 500px
@@ -254,24 +239,6 @@ html, body
a
font-weight: 800
// Overrides applying only to mobile view. This must be at the end of the overrides file.
@media only screen and (max-width: 767px)
.sidebar
margin-left: 0
border-left: none
padding-left: 0
#map
height: 300px
.navbar .nav > li
display: block
.navbar .navbar-form
width: 185px
padding-left: 0
padding-right: 0
/* override "info" alert boxes to be green, not blue, on Growstuff */
$state-info-text: darken($green, 10%)
@@ -326,3 +293,44 @@ ul.thumbnail-buttons
.hover-wrapper:hover .text
visibility: visible
.homepage-listing
padding-bottom: 6px
@media (min-width: $screen-md-min)
.planting-thumbnail
dl.planting-attributes
width: 100%
dt
text-align: left
width: 120px
dd
padding-left: 120px
margin-left: auto
.navbar .navbar-form
width: 250px
// Overrides applying only to mobile view. This must be at the end of the overrides file.
@media only screen and (max-width: 767px)
.sidebar
margin-left: 0
border-left: none
padding-left: 0
#map
height: 300px
.navbar .nav > li
display: block
.navbar .navbar-form
width: 185px
padding-left: 0
padding-right: 0
.homepage
.thumbnail
height: 180px
.seed-thumbnail
height: 220px

View File

@@ -1,53 +0,0 @@
class AccountTypesController < ApplicationController
before_action :authenticate_member!
load_and_authorize_resource
respond_to :html
# GET /account_types
def index
@account_types = AccountType.all.order(:name)
respond_with(@account_types)
end
# GET /account_types/1
def show
respond_with(@account_types)
end
# GET /account_types/new
def new
@account_type = AccountType.new
respond_with(@account_type)
end
# GET /account_types/1/edit
def edit
respond_with(@account_type)
end
# POST /account_types
def create
@account_type = AccountType.new(account_type_params)
flash[:notice] = I18n.t('account_types.created') if @account_type.save
respond_with(@account_type)
end
# PUT /account_types/1
def update
flash[:notice] = I18n.t('account_types.updated') if @account_type.update(account_type_params)
respond_with(@account_type)
end
# DELETE /account_types/1
def destroy
@account_type.destroy
flash[:notice] = I18n.t('account_types.deleted')
respond_with(@account_type)
end
private
def account_type_params
params.require(:account_type).permit(:is_paid, :is_permanent_paid, :name)
end
end

View File

@@ -1,31 +0,0 @@
class AccountsController < ApplicationController
before_action :authenticate_member!
load_and_authorize_resource
respond_to :html
# GET /accounts
def index
@accounts = Account.all.order(created_at: :desc)
respond_with(@accounts)
end
# GET /accounts/1
def show
respond_with(@account)
end
# GET /accounts/1/edit
def edit; end
# PUT /accounts/1
def update
flash[:notice] = I18n.t('account.update') if @account.update(params[:account])
respond_with(@account)
end
private
def account_params
params.require(:account).permit(:account_type_id, :member_id, :paid_until)
end
end

View File

@@ -1,23 +0,0 @@
module Admin
class OrdersController < ApplicationController
def index
authorize! :manage, :all
respond_to do |format|
format.html # index.html.haml
end
end
def search
authorize! :manage, :all
@orders = Order.search(by: params[:search_by], for: params[:search_text])
if @orders.empty?
flash[:alert] = "Couldn't find order with #{params[:search_by]} = #{params[:search_text]}"
end
respond_to do |format|
format.html # index.html.haml
end
end
end
end

View File

@@ -0,0 +1,30 @@
module Charts
class CropsController < ApplicationController
respond_to :json
def sunniness
pie_chart_query 'sunniness'
end
def planted_from
pie_chart_query 'planted_from'
end
def harvested_for
@crop = Crop.find(params[:crop_id])
render json: Harvest.joins(:plant_part)
.where(crop: @crop)
.group("plant_parts.name").count(:id)
end
private
def pie_chart_query(field)
@crop = Crop.find(params[:crop_id])
render json: Planting.where(crop: @crop)
.where.not(field.to_sym => nil)
.where.not(field.to_sym => '')
.group(field.to_sym).count(:id)
end
end
end

View File

@@ -0,0 +1,16 @@
module Charts
class GardensController < ApplicationController
respond_to :json
def timeline
@data = []
@garden = Garden.find(params[:garden_id])
@garden.plantings.where.not(planted_at: nil)
.order(finished_at: :desc).each do |p|
# use finished_at if we have it, otherwise use predictions
finish = p.finished_at.presence || p.finish_predicted_at
@data << [p.crop.name, p.planted_at, finish] if finish.present?
end
render json: @data
end
end
end

View File

@@ -51,7 +51,11 @@ class CropsController < ApplicationController
def show
@crop = Crop.includes(:scientific_names, plantings: :photos).find(params[:id])
@posts = @crop.posts.order(created_at: :desc).paginate(page: params[:page])
respond_with(@crop)
# respond_with(@crop)
respond_to do |format|
format.html
format.json { render json: @crop.to_json(crop_json_fields) }
end
end
def new

View File

@@ -1,36 +0,0 @@
class OrderItemsController < ApplicationController
before_action :authenticate_member!
load_and_authorize_resource
respond_to :html
responders :flash
# POST /order_items
def create
if params[:order_item][:price]
params[:order_item][:price] = params[:order_item][:price].to_f * 100 # convert to cents
end
@order_item = OrderItem.new(order_item_params)
@order_item.order = current_member.current_order || Order.create(member_id: current_member.id)
if @order_item.save
redirect_to @order_item.order, notice: 'Added item to your order.'
else
redirect_to shop_path, alert: errors
end
end
private
def errors
if @order_item.errors.empty?
"There was a problem with your order."
else
@order_item.errors.full_messages.to_sentence
end
end
def order_item_params
params.require(:order_item).permit(:order_id, :price, :product_id, :quantity)
end
end

View File

@@ -1,90 +0,0 @@
class OrdersController < ApplicationController
before_action :authenticate_member!
load_and_authorize_resource
# GET /orders
def index
@orders = Order.by_member(current_member)
respond_to do |format|
format.html # index.html.erb
end
end
# GET /orders/1
def show
respond_to do |format|
format.html # show.html.erb
end
end
# GET /orders/new
def new
@order = Order.new
respond_to do |format|
format.html # new.html.erb
end
end
# checkout with PayPal
def checkout
respond_to do |format|
if @order.update_attributes(referral_code: params[:referral_code])
response = EXPRESS_GATEWAY.setup_purchase(
@order.total,
items: @order.activemerchant_items,
currency: Rails.application.config.currency,
no_shipping: true,
ip: request.remote_ip,
return_url: complete_order_url,
cancel_return_url: shop_url
)
format.html { redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token) }
else
format.html { render action: "show" }
end
end
end
def complete
if params[:token] && params['PayerID']
purchase = EXPRESS_GATEWAY.purchase(
@order.total,
currency: Rails.application.config.currency,
ip: request.remote_ip,
payer_id: params['PayerID'],
token: params[:token]
)
if purchase.success?
@order.completed_at = Time.zone.now
@order.record_paypal_details(params[:token])
else
flash[:alert] = "Could not complete your order. Please notify support."
end
else
flash[:alert] = "PayPal didn't return a token or payer_id for your order. Please notify support."
end
@order.update_account # apply paid account benefits, etc.
respond_to do |format|
format.html # new.html.erb
end
end
def cancel
respond_to do |format|
format.html { redirect_to shop_url, notice: 'Order was cancelled.' }
end
end
# DELETE /orders/1
def destroy
@order.destroy
respond_to do |format|
format.html { redirect_to shop_url, notice: 'Order was deleted.' }
end
end
end

View File

@@ -88,7 +88,7 @@ class PhotosController < ApplicationController
photo = Photo.find_by(flickr_photo_id: flickr_photo_id_param)
photo ||= Photo.new(photo_params)
photo.owner_id = current_member.id
photo.set_flickr_metadata
photo.set_flickr_metadata!
photo
end

View File

@@ -31,12 +31,13 @@ class PlantingsController < ApplicationController
@planting = Planting.includes(:owner, :crop, :garden, :photos)
.friendly
.find(params[:id])
@photos = @planting.photos.order(created_at: :desc).includes(:owner).paginate(page: params[:page])
@photos = @planting.photos.order(date_taken: :desc).includes(:owner).paginate(page: params[:page])
respond_with @planting
end
def new
@planting = Planting.new(planted_at: Time.zone.today)
@seed = Seed.find_by(slug: params[:seed_id]) if params[:seed_id]
# using find_by_id here because it returns nil, unlike find
@crop = Crop.approved.find_by(id: params[:crop_id]) || Crop.new
@@ -54,7 +55,8 @@ class PlantingsController < ApplicationController
def create
@planting = Planting.new(planting_params)
@planting.owner = current_member
@planting.save
@planting.crop = @planting.parent_seed.crop if @planting.parent_seed.present?
@planting.save!
respond_with @planting
end
@@ -82,6 +84,7 @@ class PlantingsController < ApplicationController
params[:planted_at] = parse_date(params[:planted_at]) if params[:planted_at]
params.require(:planting).permit(
:crop_id, :description, :garden_id, :planted_at,
:parent_seed_id,
:quantity, :sunniness, :planted_from, :finished,
:finished_at
)

View File

@@ -1,46 +0,0 @@
class ProductsController < ApplicationController
before_action :authenticate_member!
load_and_authorize_resource
respond_to :html
responders :flash
def index
@products = Product.all.order(:name)
respond_with @products
end
def show
respond_with @product
end
def new
@product = Product.new
respond_with @product
end
def edit
respond_with @product
end
def create
@product = Product.create(product_params)
respond_with @product
end
def update
@product.update(product_params)
respond_with @product
end
def destroy
@product.destroy
respond_with @product
end
private
def product_params
params.require(:product).permit(:description, :min_price, :recommended_price, :name,
:account_type_id, :paid_months)
end
end

View File

@@ -16,44 +16,37 @@ class SeedsController < ApplicationController
respond_with(@seeds)
end
# GET /seeds/1
# GET /seeds/1.json
def show
@photos = @seed.photos.includes(:owner).order(created_at: :desc).paginate(page: params[:page])
respond_with(@seed)
end
# GET /seeds/new
# GET /seeds/new.json
def new
@seed = Seed.new
# using find_by_id here because it returns nil, unlike find
@crop = Crop.find_or_initialize_by(id: params[:crop_id])
if params[:planting_id]
@planting = Planting.find_by(slug: params[:planting_id])
else
@crop = Crop.find_or_initialize_by(id: params[:crop_id])
end
respond_with(@seed)
end
# GET /seeds/1/edit
def edit; end
# POST /seeds
# POST /seeds.json
def create
@seed = Seed.new(seed_params)
@seed.owner = current_member
@seed.crop = @seed.parent_planting.crop if @seed.parent_planting
flash[:notice] = "Successfully added #{@seed.crop} seed to your stash." if @seed.save
respond_with(@seed)
end
# PUT /seeds/1
# PUT /seeds/1.json
def update
flash[:notice] = 'Seed was successfully updated.' if @seed.update(seed_params)
respond_with(@seed)
end
# DELETE /seeds/1
# DELETE /seeds/1.json
def destroy
@seed.destroy
respond_with(@seed)
@@ -64,8 +57,11 @@ class SeedsController < ApplicationController
def seed_params
params.require(:seed).permit(
:crop_id, :description, :quantity, :plant_before,
:days_until_maturity_min, :days_until_maturity_max, :organic, :gmo,
:heirloom, :tradable_to, :slug
:parent_planting_id,
:days_until_maturity_min, :days_until_maturity_max,
:organic, :gmo,
:heirloom, :tradable_to, :slug,
:finished, :finished_at
)
end

View File

@@ -1,19 +0,0 @@
class ShopController < ApplicationController
respond_to :html
def index
@products = Product.all
@order_item = OrderItem.new
# this is (hopefully) part of a short-term hack to prevent people from
# ordering multiple subscriptions, which would be very confusing to deal
# with. We check whether they have an order already in progress, and if
# so, point that out to them and encourage them to checkout, rather than
# letting them add more stuff to their order.
@order = nil
@most_recent_item = nil
return unless current_member
@order = current_member.current_order
@most_recent_item = @order.order_items.first if @order
end
end

View File

@@ -28,7 +28,12 @@ module HarvestsHelper
end
def display_harvest_description(harvest)
return "No description provided." if harvest.description.nil?
harvest.description
if harvest.description.nil?
"no description provided."
else
truncate(harvest.description, length: 50, separator: ' ', omission: '... ') do
link_to "Read more", harvest_path(harvest)
end
end
end
end

View File

@@ -0,0 +1,51 @@
module PhotosHelper
def crop_image_path(crop)
if crop.default_photo.present?
crop.default_photo.thumbnail_url
else
placeholder_image
end
end
def garden_image_path(garden)
if garden.default_photo.present?
garden.default_photo.thumbnail_url
else
placeholder_image
end
end
def planting_image_path(planting)
if planting.photos.present?
planting.photos.first.thumbnail_url
else
placeholder_image
end
end
def harvest_image_path(harvest)
if harvest.photos.present?
harvest.photos.first.thumbnail_url
elsif harvest.planting.present? && harvest.planting.photos.present?
harvest.planting.photos.first.thumbnail_url
else
placeholder_image
end
end
def seed_image_path(seed)
if seed.default_photo.present?
seed.default_photo.thumbnail_url
elsif seed.crop.default_photo.present?
seed.crop.default_photo.thumbnail_url
else
placeholder_image
end
end
private
def placeholder_image
'placeholder_150.png'
end
end

View File

@@ -24,14 +24,9 @@ class Ability
# except these, which don't make sense if you're not logged in
cannot :read, Notification
cannot :read, Authentication
cannot :read, Order
cannot :read, OrderItem
# and nobody should be able to view this except admins
cannot :read, Role
cannot :read, Product
cannot :read, Account
cannot :read, AccountType
# nobody should be able to view unapproved crops unless they
# are wranglers or admins
@@ -116,23 +111,12 @@ class Ability
can :update, Photo, owner_id: member.id
can :destroy, Photo, owner_id: member.id
can :create, Seed
can :update, Seed, owner_id: member.id
can :create, Seed
can :update, Seed, owner_id: member.id
can :destroy, Seed, owner_id: member.id
# orders/shop/etc
can :create, Order
can :read, Order, member_id: member.id
can :complete, Order, member_id: member.id, completed_at: nil
can :checkout, Order, member_id: member.id, completed_at: nil
can :cancel, Order, member_id: member.id, completed_at: nil
can :destroy, Order, member_id: member.id, completed_at: nil
can :create, OrderItem
# for now, let's not let people mess with individual order items
cannot :read, OrderItem, order: { member_id: member.id }
cannot :update, OrderItem, order: { member_id: member.id, completed_at: nil }
cannot :destroy, OrderItem, order: { member_id: member.id, completed_at: nil }
can :create, Seed, owner_id: member.id, parent_planting: { owner_id: member.id }
can :update, Seed, owner_id: member.id, parent_planting: { owner_id: member.id }
can :destroy, Seed, owner_id: member.id, parent_planting: { owner_id: member.id }
# following/unfollowing permissions
can :create, Follow
@@ -148,12 +132,6 @@ class Ability
can :read, :all
can :manage, :all
# can't change order history, because it's *history*
cannot :create, Order
cannot :complete, Order
cannot :destroy, Order
cannot :manage, OrderItem
# can't delete plant parts if they have harvests associated with them
cannot :destroy, PlantPart
can :destroy, PlantPart do |pp|

View File

@@ -1,24 +0,0 @@
class Account < ApplicationRecord
belongs_to :member
belongs_to :account_type
validates :member_id, uniqueness: {
message: 'already has account details associated with it'
}
before_validation do
# If not account type, set to the free account
unless account_type
self.account_type = AccountType.find_or_create_by(name:
Rails.application.config.default_account_type)
end
end
def paid_until_string
if account_type.is_permanent_paid
"forever"
elsif account_type.is_paid
paid_until.to_s
end
end
end

View File

@@ -1,13 +0,0 @@
class AccountType < ApplicationRecord
#
# Relationships
has_many :products
#
# Validations
validates :name, presence: true, uniqueness: true
def to_s
name
end
end

View File

@@ -0,0 +1,12 @@
module Finishable
extend ActiveSupport::Concern
included do
scope :finished, -> { where(finished: true) }
scope :current, -> { where.not(finished: true) }
def active?
!finished
end
end
end

View File

@@ -120,12 +120,7 @@ class Crop < ApplicationRecord
# later we can choose a default photo based on different criteria,
# eg. popularity
def default_photo
# most recent photo
return photos.order(created_at: :desc).first if photos.any?
# Crop has no photos? Look for the most recent harvest with a photo.
harvest_with_photo = Harvest.where(crop_id: id).joins(:photos).order('harvests.id DESC').limit(1).first
harvest_with_photo.photos.first if harvest_with_photo
first_photo(:plantings) || first_photo(:harvests) || first_photo(:seeds)
end
# returns hash indicating whether this crop is grown in
@@ -242,4 +237,8 @@ class Crop < ApplicationRecord
return unless reason_for_rejection == "other" && rejection_notes.blank?
errors.add(:rejection_notes, "must be added if the reason for rejection is \"other\"")
end
def first_photo(type)
Photo.joins(type).where("#{type}": { crop_id: id }).order("photos.created_at DESC").first
end
end

View File

@@ -40,6 +40,13 @@ class Harvest < ApplicationRecord
##
## Scopes
default_scope { joins(:owner) } # Ensures owner exists
scope :interesting, -> { has_photos.one_per_owner }
scope :recent, -> { order(created_at: :desc) }
scope :one_per_owner, lambda {
joins("JOIN members m ON (m.id=harvests.owner_id)
LEFT OUTER JOIN harvests h2
ON (m.id=h2.owner_id AND harvests.id < h2.id)").where("h2 IS NULL")
}
##
## Validations

View File

@@ -7,7 +7,7 @@ class Member < ApplicationRecord
friendly_id :login_name, use: %i(slugged finders)
#
# Relationshops
# Relationships
has_many :posts, foreign_key: 'author_id'
has_many :comments, foreign_key: 'author_id'
has_many :forums, foreign_key: 'owner_id'
@@ -19,9 +19,6 @@ class Member < ApplicationRecord
has_many :notifications, foreign_key: 'recipient_id'
has_many :sent_notifications, foreign_key: 'sender_id'
has_many :authentications
has_many :orders
has_one :account
has_one :account_type, through: :account
has_many :photos
has_many :requested_crops, class_name: Crop, foreign_key: 'requester_id'
has_many :likes, dependent: :destroy
@@ -77,7 +74,11 @@ class Member < ApplicationRecord
after_validation :geocode
after_validation :empty_unwanted_geocodes
after_save :update_newsletter_subscription
after_create :create_account_and_garden
# Give each new member a default garden
# we use find_or_create to avoid accidentally creating a second one,
# which can happen sometimes especially with FactoryBot associations
after_create { |member| Garden.create(name: "Garden", owner_id: member.id) }
# allow login via either login_name or email address
def self.find_first_by_auth_conditions(warden_conditions)
@@ -95,34 +96,6 @@ class Member < ApplicationRecord
roles.any? { |r| r.name.gsub(/\s+/, "_").underscore.to_sym == role_sym }
end
def current_order
orders.find_by(completed_at: nil)
end
# when purchasing a product that gives you a paid account, this method
# does all the messing around to actually make sure the account is
# updated correctly -- account type, paid until, etc. Usually this is
# called by order.update_account, which loops through all order items
# and does this for each one.
def update_account_after_purchase(product)
account.account_type = product.account_type if product.account_type
if product.paid_months
start_date = account.paid_until || Time.zone.now
account.paid_until = start_date + product.paid_months.months
end
account.save
end
def paid?
if account.account_type.is_permanent_paid
true
elsif account.account_type.is_paid && account.paid_until >= Time.zone.now
true
else
false
end
end
def auth(provider)
authentications.find_by(provider: provider)
end
@@ -232,13 +205,4 @@ class Member < ApplicationRecord
def get_follow(member)
follows.find_by(followed_id: member.id) if already_following?(member)
end
# Give each new member a default garden
# and an account record (for paid accounts etc)
# we use find_or_create to avoid accidentally creating a second one,
# which can happen sometimes especially with FactoryBot associations
def create_account_and_garden
Garden.create!(name: "Garden", owner_id: id)
Account.find_or_create_by!(member_id: id)
end
end

View File

@@ -1,90 +0,0 @@
class Order < ApplicationRecord
#
# Relationships
belongs_to :member, -> { with_deleted }
has_many :order_items, dependent: :destroy
#
# Validations
validates :referral_code, format: {
with: /\A[a-zA-Z0-9 ]*\z/,
message: "may only include letters and numbers"
}
#
# Teiggers
before_save :standardize_referral_code
#
# Scopes
scope :by_member, ->(member) { where(member: member) }
# total price of an order
def total
sum = 0
order_items.each do |i|
subtotal = i.price * i.quantity
sum += subtotal
end
sum
end
# return items in the format ActiveMerchant/PayPal want them
def activemerchant_items
items = []
order_items.each do |i|
items.push(name: i.product.name,
quantity: i.quantity,
amount: i.price)
end
items
end
# record the paypal details for reference
def record_paypal_details(token)
self.paypal_express_token = token
details = EXPRESS_GATEWAY.details_for(token)
self.paypal_express_payer_id = details.payer_id
save
end
# when an order is completed, we update the member's account to mark
# them as paid, or whatever, based on what products they ordered
def update_account
order_items.each do |i|
member.update_account_after_purchase(i.product)
end
end
# removes whitespace and forces to uppercase (we're somewhat liberal
# in what we accept, but we clean it up anyway.)
def standardize_referral_code
self.referral_code = referral_code.upcase.gsub(/\s/, '') if referral_code
end
# search orders (used by admin/orders)
# usage: Order.search({ :by => 'member', :for => 'Skud' })
# can search by: member, order_id, paypal_token, paypal_payer_id,
def self.search(args = {})
if args[:for]
case args[:by]
when "member"
member = Member.with_deleted.find_by(login_name: args[:for])
return member.orders if member
when "order_id"
order = Order.find_by(id: args[:for])
return [order] if order
when "paypal_token"
order = Order.find_by(paypal_express_token: args[:for])
return [order] if order
when "paypal_payer_id"
order = Order.find_by(paypal_express_payer_id: args[:for])
return [order] if order
when "referral_code"
# coerce to uppercase
return Order.where(referral_code: args[:for].upcase)
end
end
[]
end
end

View File

@@ -1,12 +0,0 @@
class OrderItem < ApplicationRecord
belongs_to :order
belongs_to :product
validate :price_must_be_greater_than_minimum
validates :order_id, uniqueness: { message: "may only have one item." }
def price_must_be_greater_than_minimum
@product = Product.find(product_id)
errors.add(:price, "must be greater than the product's minimum value") if price < @product.min_price
end
end

View File

@@ -27,7 +27,8 @@ class Photo < ApplicationRecord
license_url: license.url,
thumbnail_url: FlickRaw.url_q(info),
fullsize_url: FlickRaw.url_z(info),
link_url: FlickRaw.url_photopage(info)
link_url: FlickRaw.url_photopage(info),
date_taken: info.dates.taken
}
end
@@ -49,7 +50,11 @@ class Photo < ApplicationRecord
end
end
def set_flickr_metadata
def set_flickr_metadata!
update_attributes(flickr_metadata)
end
def to_s
"#{title} by #{owner.login_name}"
end
end

View File

@@ -1,6 +1,7 @@
class Planting < ApplicationRecord
extend FriendlyId
include PhotoCapable
include Finishable
friendly_id :planting_slug, use: %i(slugged finders)
# Constants
@@ -20,11 +21,15 @@ class Planting < ApplicationRecord
belongs_to :crop, counter_cache: true
has_many :harvests, dependent: :destroy
#
# Ancestry of food
belongs_to :parent_seed, class_name: 'Seed', foreign_key: 'parent_seed_id' # parent
has_many :child_seeds, class_name: 'Seed',
foreign_key: 'parent_planting_id', dependent: :nullify # children
##
## Scopes
default_scope { joins(:owner) } # Ensures the owner still exists
scope :finished, -> { where(finished: true) }
scope :current, -> { where(finished: false) }
scope :interesting, -> { has_photos.one_per_owner }
scope :recent, -> { order(created_at: :desc) }
scope :one_per_owner, lambda {

View File

@@ -1,15 +0,0 @@
class Product < ApplicationRecord
#
# Relationships
belongs_to :account_type
has_and_belongs_to_many :orders # rubocop:disable Rails/HasAndBelongsToMany
#
# Validations
validates :paid_months, allow_nil: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validates :min_price, presence: true
def to_s
name
end
end

View File

@@ -1,6 +1,7 @@
class Seed < ApplicationRecord
extend FriendlyId
include PhotoCapable
include Finishable
friendly_id :seed_slug, use: %i(slugged finders)
TRADABLE_TO_VALUES = %w(nowhere locally nationally internationally).freeze
@@ -13,11 +14,13 @@ class Seed < ApplicationRecord
belongs_to :crop
belongs_to :owner, class_name: 'Member', foreign_key: 'owner_id', counter_cache: true
belongs_to :parent_planting, class_name: 'Planting', foreign_key: 'parent_planting_id' # parent
has_many :child_plantings, class_name: 'Planting',
foreign_key: 'parent_seed_id', dependent: :nullify # children
#
# Validations
validates :crop, approved: true
delegate :name, to: :crop
delegate :default_photo, to: :crop
validates :crop, presence: { message: "must be present and exist in our database" }
validates :quantity, allow_nil: true,
numericality: { only_integer: true, greater_than_or_equal_to: 0 }
@@ -38,6 +41,10 @@ class Seed < ApplicationRecord
inclusion: { in: HEIRLOOM_VALUES, message: "You must say whether the seeds"\
"are heirloom, hybrid, or unknown" }
#
# Delegations
delegate :name, to: :crop
#
# Scopes
default_scope { joins(:owner) } # Ensure owner exists
@@ -45,6 +52,10 @@ class Seed < ApplicationRecord
scope :interesting, -> { tradable.has_location }
scope :has_location, -> { joins(:owner).where.not("members.location": nil) }
def default_photo
photos.order(created_at: :desc).first
end
def tradable?
tradable_to != 'nowhere'
end

View File

@@ -1,21 +0,0 @@
= form_for @account_type do |f|
- if @account_type.errors.any?
#error_explanation
%h2
= pluralize(@account_type.errors.size, "error")
prohibited this account_type from being saved:
%ul
- @account_type.errors.full_messages.each do |msg|
%li= msg
.field
= f.label :name
= f.text_field :name
.field
= f.label :is_paid
= f.check_box :is_paid
.field
= f.label :is_permanent_paid
= f.check_box :is_permanent_paid
.actions
= f.submit 'Save'

View File

@@ -1,7 +0,0 @@
- content_for :title, "Editing account type"
= render 'form'
= link_to 'Show', @account_type
\|
= link_to 'Back', account_types_path

View File

@@ -1,23 +0,0 @@
- content_for :title, "Listing account types"
%table
%tr
%th Name
%th Is paid
%th Is permanent paid
%th
%th
%th
- @account_types.each do |account_type|
%tr
%td= account_type.name
%td= account_type.is_paid
%td= account_type.is_permanent_paid
%td= link_to 'Show', account_type
%td= link_to 'Edit', edit_account_type_path(account_type)
%td= link_to 'Destroy', account_type, method: :delete, data: { confirm: 'Are you sure?' }
%br
= link_to 'New Account type', new_account_type_path

View File

@@ -1,5 +0,0 @@
- content_for :title, "New account type"
= render 'form'
= link_to 'Back', account_types_path

View File

@@ -1,17 +0,0 @@
%p#notice= notice
%p
%b Name:
= @account_type.name
%p
%b Is paid:
= @account_type.is_paid
%p
%b Is permanent paid:
= @account_type.is_permanent_paid
= link_to 'Edit', edit_account_type_path(@account_type)
\|
= link_to 'Delete', @account_type, method: :delete, data: { confirm: 'Are you sure?' }
\|
= link_to 'Back', account_types_path

View File

@@ -1,21 +0,0 @@
= form_for @account do |f|
- if @account.errors.any?
#error_explanation
%h2
= pluralize(@account.errors.size, "error")
prohibited this account from being saved:
%ul
- @account.errors.full_messages.each do |msg|
%li= msg
.field
= f.label :member_id
= f.number_field :member_id
.field
= f.label :account_type
= f.text_field :account_type
.field
= f.label :paid_until
= f.datetime_select :paid_until
.actions
= f.submit 'Save'

View File

@@ -1,7 +0,0 @@
- content_for :title, "Editing account"
= render 'form'
= link_to 'Show', @account
\|
= link_to 'Back', accounts_path

View File

@@ -1,23 +0,0 @@
- content_for :title, "Listing accounts"
%table
%tr
%th Member
%th Account type
%th Paid until
%th
%th
%th
- @accounts.each do |account|
%tr
%td= account.member_id
%td= account.account_type
%td= account.paid_until
%td= link_to 'Show', account
%td= link_to 'Edit', edit_account_path(account)
%td= link_to 'Destroy', account, method: :delete, data: { confirm: 'Are you sure?' }
%br
= link_to 'New Account detail', new_account_path

View File

@@ -1,5 +0,0 @@
- content_for :title, "New account"
= render 'form'
= link_to 'Back', accounts_path

View File

@@ -1,15 +0,0 @@
%p#notice= notice
%p
%b Member:
= @account.member_id
%p
%b Account type:
= @account.account_type.name
%p
%b Paid until:
= @account.paid_until
= link_to 'Edit', edit_account_path(@account)
\|
= link_to 'Back', accounts_path

View File

@@ -6,8 +6,6 @@
.col-md-4
%h2 Site admin
%ul#site_admin
%li= link_to "Account types", account_types_path
%li= link_to "Products", products_path
%li= link_to "Roles", roles_path
%li= link_to "Forums", forums_path
-# %li= link_to "CMS", comfy_admin_cms_path
@@ -22,8 +20,3 @@
%ul
%li= link_to "Newsletter subscribers", admin_newsletter_path
%li= link_to "Members", admin_members_path
.row
.col-md-12
%h2 Orders
= render "admin/orders/searchform"

View File

@@ -11,5 +11,5 @@
%th
- @members.each do |member|
%tr
%td= ember.login_name
%td= member.login_name
%td= member.email

View File

@@ -1,8 +0,0 @@
= form_tag(url_for(controller: 'admin/orders', action: 'search'), method: :get, class: 'form-inline') do
= label_tag :distance, "Search orders:", class: 'control-label'
= text_field_tag :search_text
= select_tag :search_by,
options_for_select('Member': 'member', 'Referral code': 'referral_code',
'Order ID': 'order_id', 'Paypal Token': 'paypal_token',
'Paypal Payer ID': 'paypal_payer_id')
= submit_tag "Search", class: 'btn btn-primary'

View File

@@ -1,3 +0,0 @@
- content_for :title, 'Admin Orders'
= render "admin/orders/searchform"

View File

@@ -1,41 +0,0 @@
- content_for :title, 'Search Orders'
= render "admin/orders/searchform"
- unless @orders.empty?
%h2
Found
= pluralize(@orders.size, "result")
%table.table.table-striped
%tr
%th Member
%th Order number
%th Date completed
%th Referral code
%th Items
%th
- @orders.each do |order|
%tr
%td
= link_to order.member.login_name, order.member
= "(deleted)" if order.member.deleted_at
%td= order.id
%td
- if order.completed_at
= order.completed_at.to_s
- else
In progress
%td
= order.referral_code
%td
- unless order.order_items.empty?
- order.order_items.each do |o|
= o.quantity
x
= o.product.name
@
= price_with_currency(o.price)
%br/
%td= link_to 'Details', order, class: 'btn btn-default btn-xs'

View File

@@ -0,0 +1,8 @@
- if can? :create, Planting
= link_to "Plant this", new_planting_path(crop_id: crop.id), class: 'btn btn-default'
- if can? :create, Harvest
= link_to "Harvest this", new_harvest_path(crop_id: crop.id), class: 'btn btn-default'
- if can? :create, Seed
= link_to 'Add seeds to stash', new_seed_path(params: { crop_id: crop.id }), class: 'btn btn-default'

View File

@@ -1,5 +1,5 @@
- cache crop do
= link_to image_tag(crop.default_photo.present? ? crop.default_photo.thumbnail_url : 'placeholder_150.png',
= link_to image_tag(crop_image_path(crop),
alt: crop.name, class: 'image-responsive crop-image'),
crop.name,
rel: "popover",

View File

@@ -1,7 +1,7 @@
.well
.row
.col-md-4
= link_to image_tag((crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png'),
= link_to image_tag(crop_image_path(crop),
alt: '',
class: 'img crop-image'),
crop

View File

@@ -8,7 +8,7 @@
- unless crop.photos.empty?
%h3 Photos of #{crop.name} plants
.row
- crop.photos.first(6).each do |p|
- crop.photos.order(date_taken: :desc).first(6).each do |p|
.col-xs-6.col-md-2
= render "photos/thumbnail", photo: p
.row

View File

@@ -1,8 +1,8 @@
.thumbnail
.crop-thumbnail
- if crop
- cache cache_key_for(Crop, crop.id) do
= link_to image_tag((crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png'),
- cache cache_key_for(Crop, crop.id) do
.thumbnail
.crop-thumbnail
- if crop
= link_to image_tag(crop_image_path(crop),
alt: crop.name, class: 'img'),
crop
.cropinfo

View File

@@ -8,18 +8,14 @@
= tag("meta", property: "og:url", content: request.original_url)
= tag("meta", property: "og:site_name", content: ENV['GROWSTUFF_SITE_NAME'])
- content_for :scripts do
= javascript_include_tag "charts"
= render partial: 'approval_status_message', locals: { crop: @crop }
- if @crop.approved?
- content_for :buttonbar do
- if can? :create, Planting
= link_to "Plant this", new_planting_path(crop_id: @crop.id), class: 'btn btn-default'
- if can? :create, Harvest
= link_to "Harvest this", new_harvest_path(crop_id: @crop.id), class: 'btn btn-default'
- if can? :create, Seed
= link_to 'Add seeds to stash', new_seed_path(params: { crop_id: @crop.id }), class: 'btn btn-default'
= render 'crops/actions', crop: @crop
.row
.col-md-9

View File

@@ -1,28 +1,29 @@
- if can?(:edit, garden) || can?(:delete, garden)
- if can? :edit, garden
- if garden.active
= link_to new_planting_path(garden_id: garden.id), class: 'btn btn-primary' 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',
data: { confirm: 'All plantings associated with this garden will be marked as finished. Are you sure?' }
- else
= link_to "Mark as active", garden_path(garden, garden: { active: 1 }),
method: :put,
class: 'btn btn-default'
= link_to edit_garden_path(garden), class: 'btn btn-default', id: 'edit_garden_link' do
%span.glyphicon.glyphicon-pencil{ title: "Edit garden" }
Edit
.garden-actions
- if can?(:edit, garden)
.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?' }
- else
= link_to "Mark as active", garden_path(garden, garden: { active: 1 }),
method: :put
= render 'shared/buttons/edit', path: edit_garden_path(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
- if can?(:destroy, garden)
= link_to garden,
method: :delete,
data: { confirm: 'All plantings associated with this garden will also be deleted. Are you sure?' },
class: 'btn btn-default', id: 'delete_garden_link' do
%span.glyphicon.glyphicon-trash{ title: "Delete" }
Delete
- if can?(:edit, garden) && can?(:create, Photo)
= link_to new_photo_path(type: "garden", id: garden.id),
class: 'btn btn-primary' do
%span.glyphicon.glyphicon-camera{ title: "Add Photo" }
Add Photo
.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

View File

@@ -4,12 +4,7 @@
= link_to "Everyone's gardens", gardens_path, class: 'btn btn-default'
= link_to gardens_active_tickbox_path(@owner, show_all) do
= check_box_tag 'active', 'all', show_all
include in-active
- if can?(:create, Garden)
= link_to 'Add a garden', new_garden_path, class: 'btn btn-primary'
- unless current_member
= render partial: 'shared/signin_signup', locals: { to: 'add a new garden' }
- 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,9 +1,7 @@
.panel.panel-success
.panel-heading
%h3.panel-title
= link_to garden.name, garden_path(garden)
.panel-body
.row
.col-md-2.col-xs-12.garden-info
@@ -11,15 +9,17 @@
.col-md-12.col-xs-6
= render 'gardens/photo', garden: garden
.col-md-12.col-xs-6
= render 'gardens/actions', garden: garden
= display_garden_description(garden)
.col-md-10
.row
- if garden.plantings.current.size.positive?
- garden.plantings.current.includes(:crop).each do |planting|
.col-md-2.col-sm-6.col-xs-6
.hover-wrapper
.text= render 'plantings/actions', planting: planting
.text
= render 'plantings/actions', planting: planting
= render partial: "plantings/thumbnail", locals: { planting: planting }
- else
no plantings
-# .panel-footer
.col-md-2.col-sm-6.col-xs-6 no plantings
- if can?(:edit, garden)
.panel-footer= render 'gardens/actions', garden: garden

View File

@@ -1,3 +1,3 @@
= link_to image_tag((garden.default_photo ? garden.default_photo.thumbnail_url : 'placeholder_150.png'),
= link_to image_tag(garden_image_path(garden),
alt: garden.name, class: 'img-responsive'),
garden_path(garden)

View File

@@ -8,7 +8,7 @@
.panel-body{ id: "gardens_panel_body" }
.row
.col-md-4
= link_to image_tag((garden.default_photo ? garden.default_photo.thumbnail_url : 'placeholder_150.png'),
= link_to image_tag(garden_image_path(garden),
alt: garden.name, class: 'img'),
garden_path(garden)
.col-md-8

View File

@@ -1,6 +1,10 @@
- content_for :title, @owner ? "#{@owner}'s gardens" : "Everyone's gardens"
= render 'nav', owner: @owner, show_all: @show_all
= render 'nav'
= link_to gardens_active_tickbox_path(@owner, @show_all) do
= check_box_tag 'active', 'all', @show_all
include in-active
.pagination
= page_entries_info @gardens

View File

@@ -11,11 +11,13 @@
= tag("meta", property: "og:site_name", content: ENV['GROWSTUFF_SITE_NAME'])
- content_for :scripts do
= javascript_include_tag "charts"
= javascript_include_tag "https://www.gstatic.com/charts/loader.js"
.row
.col-md-9
%p.btn-group= render 'gardens/actions', garden: @garden
= render 'gardens/actions', garden: @garden
- unless @garden.active
.alert.alert-warning
@@ -25,20 +27,21 @@
to plant something in this garden.
%div
:growstuff_markdown
#{strip_tags @garden.description}
- unless @garden.description
.row-fluid
%p No description available yet.
%p
:growstuff_markdown
#{strip_tags @garden.description}
- unless @garden.description
.row-fluid
%p No description available yet.
- if can? :edit, @garden
%p
Why not
= link_to 'tell us more.', edit_garden_path(@garden)
- if can? :edit, @garden
%p
Why not
= link_to 'tell us more.', edit_garden_path(@garden)
%h3 Garden timeline
.row
= timeline garden_timeline_path(@garden), adapter: "google"
.col-md-12= timeline garden_timeline_path(@garden), adapter: "google"
%h3 Current plantings in garden
.row

View File

@@ -0,0 +1,6 @@
- if can?(:edit, harvest) || can?(:destroy, harvest)
.btn-group.harvest-actions
- 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)

View File

@@ -8,7 +8,7 @@
.panel-body
.row
.col-md-4
= link_to image_tag((harvest.default_photo ? harvest.default_photo.thumbnail_url : 'placeholder_150.png'),
= link_to image_tag(harvest_image_path(harvest),
alt: harvest.crop.name, class: 'img'),
harvest
.col-md-8
@@ -21,9 +21,11 @@
%dd= display_quantity(harvest)
%dt Harvest date :
%dd= harvest.harvested_at
.panel-footer
%dt Description
%dd.truncate
= display_harvest_description(harvest)
= if harvest.description.present?
- link_to "Read more", harvest_path(harvest)
%dd Notes:
%dt=display_harvest_description(harvest)
- if harvest.planting.present?
%dt Harvested from
%dd= link_to(harvest.planting, planting_path(harvest.planting))
.row
.col-md-12
= render 'harvests/actions', harvest: harvest

View File

@@ -0,0 +1,9 @@
= link_to image_tag(harvest_image_path(harvest),
alt: harvest.to_s,
class: 'image-responsive crop-image'),
harvest,
rel: "popover",
'data-trigger': 'hover',
'data-title': harvest.to_s,
'data-content': render('harvests/popover', harvest: harvest),
'data-html': true

View File

@@ -0,0 +1,11 @@
- harvests.each do |h|
- cache h do
.row
.col-md-3.col-xs-4{ style: 'padding-bottom: 6px' }
= render 'harvests/image_with_popover', harvest: h
.col-md-9.col-xs-4
= link_to h.crop, crop_path(h.crop)
%br/
%small
%i
= h.owner.location

View File

@@ -0,0 +1,3 @@
%p
%small
= harvest.harvested_at

View File

@@ -1,9 +1,10 @@
.thumbnail
.harvest-thumbnail
- if harvest
= link_to image_tag((harvest.default_photo ? harvest.default_photo.thumbnail_url : 'placeholder_150.png'),
= link_to image_tag(harvest_image_path(harvest),
alt: harvest.crop.name, class: 'img'),
harvest
.harvestinfo
.harvest-name
= link_to harvest, harvest
= I18n.l(harvest.harvested_at.to_date)

View File

@@ -32,13 +32,7 @@
%b Quantity:
= display_quantity(@harvest)
- if can?(:edit, @harvest) || can?(:destroy, @harvest)
%p
- if can? :edit, @harvest
= link_to 'Edit', edit_harvest_path(@harvest), class: 'btn btn-default btn-xs'
- if can? :destroy, @harvest
= link_to 'Delete', @harvest, method: :delete, data: { confirm: 'Are you sure?' },
class: 'btn btn-default btn-xs'
= render 'harvests/actions', harvest: @harvest
.col-md-6
= render partial: "crops/index_card", locals: { crop: @harvest.crop }

View File

@@ -1,28 +1,5 @@
.row
.col-md-8
- cache cache_key_for(Crop, 'interesting'), expires_in: 1.day do
%h2= t('.our_crops')
.hidden-xs
- Crop.interesting.includes(:scientific_names, :photos).first(8).each do |c|
.col-md-3
= render partial: 'crops/thumbnail', locals: { crop: c }
.visible-xs
- Crop.interesting.includes(:scientific_names, :photos).first(3).each do |c|
.col-md-3
= render partial: 'crops/thumbnail', locals: { crop: c }
.col-md-4.hidden-xs
- cache cache_key_for(Planting) do
%h2= t('.recently_planted')
= render 'plantings/list', plantings: Planting.includes(:owner, :photos).interesting.recent.first(6)
.row
.col-md-12
- cache cache_key_for(Crop, 'recent') do
%p{ style: 'margin-top: 11.25px' }
%strong
#{t('.recently_added')}:
!= Crop.recent.limit(12).map { |c| link_to(c, c) }.join(", ")
%p.text-right
= link_to "#{t('.view_all')} »", crops_path
- cache cache_key_for(Crop, 'interesting'), expires_in: 1.day do
.row
%h2= t('.our_crops')
- Crop.interesting.includes(:scientific_names, :photos).limit(8).each do |c|
.col-md-4.col-sm-3.col-xs-6= render 'crops/thumbnail', crop: c

View File

@@ -1,6 +1,6 @@
%h2= t('.discussion')
- posts = Post.limit(6)
- posts = Post.order(created_at: :desc).limit(6)
- if posts
= render "posts/summary", posts: posts, howmany: 6

View File

@@ -0,0 +1,3 @@
- cache cache_key_for(Harvest) do
%h2 Recently Harvested
= render 'harvests/list', harvests: Harvest.includes(:crop, :owner, :photos).has_photos.recent.first(5)

View File

@@ -1,13 +1,13 @@
- cache cache_key_for(Member) do
.hidden-xs
- members = Member.interesting.first(6)
- members = Member.includes(plantings: :crop).interesting.first(6)
- if members.present?
%section
%h2= t('.title')
.member-cards
- members.each do |m|
= render partial: "members/thumbnail", locals: { member: m }
= render "members/thumbnail", member: m
%p.text-right
= link_to "#{t('.view_all')} »", members_path

View File

@@ -0,0 +1,3 @@
- cache cache_key_for(Planting, 'home'), expires_in: 1.day do
%h2= t('.recently_planted')
= render 'plantings/list', plantings: Planting.includes(:crop, garden: :owner).has_photos.recent.limit(5)

View File

@@ -1,21 +1,22 @@
- cache cache_key_for(Seed, 'interesting'), expires_in: 1.day do
%h2= t('.title')
.row
.col-md-8
- Seed.includes(:owner, crop: :photos).order(created_at: :desc).interesting.first(6).each do |seed|
.col-md-3
.thumbnail
- cache cache_key_for(Crop, seed.id) do
= link_to image_tag((seed.default_photo ? seed.default_photo.thumbnail_url : 'placeholder_150.png'),
alt: seed.crop.name, class: 'img'),
seed
.seedinfo
= link_to seed.crop.name, seed
.trade-to
%p= seed.owner.location
%p
- Seed.current.tradable.order(created_at: :desc).limit(6).each do |seed|
.col-md-2.col-sm-2.col-xs-6
.thumbnail.seed-thumbnail
- cache cache_key_for(Crop, seed.id) do
= link_to image_tag(seed_image_path(seed),
alt: seed.crop.name, class: 'img'),
seed
.seedinfo
= link_to seed.crop.name, seed
.trade-to
%p= seed.owner.location
%p
%small
Will trade to:
%br/
#{seed.tradable_to}
%em= seed.tradable_to
%p.text-right
= link_to "#{t('.view_all')} »", seeds_path

View File

@@ -1,9 +1,9 @@
.row
.homepage.row
.col-md-12
- if member_signed_in?
%h1= t('.welcome', site_name: ENV['GROWSTUFF_SITE_NAME'], member_name: current_member)
= render partial: 'stats'
= render 'stats'
%p
.btn-group
= link_to t('.plant'), new_planting_path, class: 'btn btn-default'
@@ -14,12 +14,30 @@
- else
.hidden-xs
.jumbotron
= render partial: 'blurb'
= render 'blurb'
.visible-xs
= render partial: 'blurb'
= render 'blurb'
= render partial: 'crops'
= render partial: 'seeds'
= render partial: 'members'
= render partial: 'discuss'
.row
.col-md-6.col-sm-12
= render 'crops'
.col-md-3.col-sm-6
= render 'plantings'
.col-md-3.col-sm-6
= render 'harvests'
.col-md-12
- cache cache_key_for(Crop, 'recent') do
%p{ style: 'margin-top: 11.25px' }
%strong
#{t('.recently_added')}:
!= Crop.recent.limit(30).map { |c| link_to(c, c) }.join(", ")
%p.text-right
= link_to "#{t('home.crops.view_all')} »", crops_path
.row
.col-md-12
= render 'seeds'
= render 'members'
.row
.col-md-12
= render 'discuss'

View File

@@ -47,7 +47,6 @@
%li= link_to t('.browse_members'), members_path
%li= link_to t('.posts'), posts_path
%li= link_to t('.forums'), forums_path
%li= link_to t('.support_growstuff'), shop_path
- if member_signed_in?
%li.dropdown<
@@ -64,7 +63,6 @@
%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('.account'), orders_path
%li
- if current_member.notifications.unread_count.positive?
= link_to(t('.inbox_unread', unread_count: current_member.notifications.unread_count),

View File

@@ -17,9 +17,7 @@
%small= yield(:subtitle)
- if content_for?(:buttonbar)
%p
.btn-group
= yield(:buttonbar)
.btn-group.layout-actions= yield(:buttonbar)
= render partial: "shared/flash_messages", flash: flash
= yield
@@ -29,4 +27,5 @@
Javascripts
\==================================================
/ Placed at the end of the document so the pages load faster
= javascript_include_tag "application"
!= Growstuff::Application.config.analytics_code

View File

@@ -1,24 +0,0 @@
%h3 Account details
%p
%strong Member since:
= member.created_at.to_s(:date)
%p
%strong Account type:
= member.account_type
account
%p
%strong Last Login:
= member.last_sign_in_at
%p
%strong Member Roles:
%br
- if member.role? :admin
Administrator
- if member.role? :crop_wrangler
Crop Wrangler
- else
Member

View File

@@ -0,0 +1,9 @@
%p
%strong Member Roles:
%br
- if member.role? :admin
Administrator
- if member.role? :crop_wrangler
Crop Wrangler
- unless (member.role?(:admin) || member.role?(:crop_wrangler))
Member

View File

@@ -1,3 +1,10 @@
%p
%strong Member since:
= member.created_at.to_s(:date)
%p
%strong Last Login:
= member.last_sign_in_at
%h3 Activity
%ul.list-inline
@@ -33,4 +40,3 @@
= link_to pluralize(member.followers.size, "follower"), member_followers_path(member)
- else
0 followers

View File

@@ -10,8 +10,6 @@
- content_for :buttonbar do
- if can? :update, @member
= link_to 'Edit profile', edit_member_registration_path, class: 'btn btn-default'
- if @member == current_member && !@member.paid?
= link_to "Upgrade account", shop_path, class: 'btn btn-default'
- if can?(:create, Notification) && current_member != @member
= link_to 'Send message', new_notification_path(recipient_id: @member.id), class: 'btn btn-default'
@@ -33,7 +31,7 @@
= render partial: "gardens", locals: { member: @member, gardens: @gardens }
.col-md-3
= render partial: "avatar", locals: { member: @member }
= render partial: "account", locals: { member: @member }
= render partial: "roles", locals: { member: @member }
= render partial: "stats", locals: { member: @member }
= render partial: "contact", locals: { member: @member,
twitter_auth: @twitter_auth,

View File

@@ -1,45 +0,0 @@
- content_for :title, "Completed order"
%p Thank you for your order.
%p
%strong Completed at:
= @order.completed_at
%p
%strong Order number:
= @order.id
= render "shared/account_status"
%h2 Order items
%table.table.table-striped
%tr
%th Product
%th Price
%th Quantity
%th Subtotal
- total = 0
- @order.order_items.each do |i|
%tr
%td= i.product.name
%td
= price_with_currency(i.price)
%td= i.quantity
%td
- subtotal = i.price * i.quantity
- total += subtotal
= price_with_currency(subtotal)
%tr
%td
%td
%td
%strong Total:
%td
%strong
= price_with_currency(total)
%p
= link_to "View other orders/order history", orders_path

View File

@@ -1,44 +0,0 @@
- content_for :title, "Your Account"
= render "shared/account_status"
%h2 Orders
- if current_member.orders.present?
%p
Your order history shows what you have bought via our
= succeed "." do
= link_to "shop", shop_path
%table.table.table-striped
%tr
%th Order number
%th Date completed
%th Items
%th
- @orders.each do |order|
%tr
%td= order.id
%td
- if order.completed_at
= order.completed_at.to_s
- else
In progress
%td
- unless order.order_items.empty?
- order.order_items.each do |o|
= o.quantity
x
= o.product.name
@
= price_with_currency(o.price)
%br/
%td= link_to 'Details', order, class: 'btn btn-default btn-xs'
- else
%p
You have not made any orders. You can place an order via our
= succeed "." do
= link_to "shop", shop_path

View File

@@ -1,84 +0,0 @@
- content_for :title, @order.completed_at ? "Order details (##{@order.id})" : "Current order"
%p
%strong Order number:
= @order.id
%p
%strong Ordered by:
= link_to @order.member, @order.member
%p
%strong Date begun:
= @order.created_at.to_s
- if @order.completed_at
%p
%strong Date completed:
= @order.completed_at.to_s
- if @order.referral_code
%p
%strong Referral code:
= @order.referral_code
- if current_member.role? :admin
%p
%strong Paypal Express token:
= @order.paypal_express_token
%p
%strong Paypal Express payer ID:
= @order.paypal_express_payer_id
%h2 Order items
%table.table.table-striped
%tr
%th Product
%th Price
%th Quantity
%th Subtotal
- @order.order_items.each do |i|
%tr
%td= i.product.name
%td
= price_with_currency(i.price)
%td= i.quantity
%td
- subtotal = i.price * i.quantity
= price_with_currency(subtotal)
%tr
%td
%td
%td
%strong Total:
%td
%strong
= price_with_currency(@order.total)
= forex_link(@order.total)
- if @order.errors.any?
.alert
#error_explanation
%h3
= pluralize(@order.errors.size, "error")
stopped you from checking out:
%ul
- @order.errors.full_messages.each do |msg|
%li= msg
- if can?(:complete, @order) || can?(:destroy, @order)
= form_tag(checkout_order_path(@order), method: :get, class: 'form-inline') do
%p
- if can? :complete, @order
= label_tag :referral_code, "Do you have a referral code?"
= text_field_tag :referral_code, @order.referral_code, class: 'input-medium'
= submit_tag "Checkout with PayPal", class: 'btn btn-primary'
- if can? :destroy, @order
= link_to 'Delete this order', @order, method: :delete,
data: { confirm: 'Are you sure?' },
class: 'btn btn-default'
= link_to "View other orders/order history", orders_path, class: 'btn btn-default'
%p

View File

@@ -0,0 +1,6 @@
- if can?(:edit, @photo) && can?(:destroy, @photo)
%p.photo-actions
- if can?(:edit, @photo)
= render 'shared/buttons/edit', path: edit_photo_path(@photo)
- if can?(:destroy, @photo)
= render 'shared/buttons/delete', path: photo_path(@photo)

View File

@@ -1,16 +1,14 @@
%h2 Photos
- if photos.size.positive? || (can?(:edit, item) && can?(:create, Photo))
%h2 Photos
- if photos.size.positive?
= page_entries_info photos
= will_paginate photos
.row
.pagination
= page_entries_info photos
= will_paginate photos
.row
- photos.each do |photo|
.col-md-2.six-across= render 'photos/thumbnail', photo: photo
- if can?(:create, Photo) && can?(:edit, item)
.col-md-2
.thumbnail
= link_to new_photo_path(type: type, id: item.id), class: 'btn btn-primary' do
%span.glyphicon.glyphicon-camera{ title: "Add photo" }
Add photo
- photos.each do |photo|
.col-xs-6.col-md-3.six-across= render 'photos/thumbnail', photo: photo
- if can?(:create, Photo) && can?(:edit, item)
= link_to new_photo_path(type: type, id: item.id), class: 'btn btn-primary' do
%span.glyphicon.glyphicon-camera{ title: "Add photo" }
Add photo

View File

@@ -1,10 +1,12 @@
.thumbnail.photo-thumbnail
= link_to image_tag(photo.thumbnail_url, alt: photo.title, class: 'img img-responsive'), photo
.text
%p
= link_to photo.title, photo
%br/
%small
%i
by
= link_to photo.owner, photo.owner
.thumbnail
.photo-thumbnail
= link_to image_tag(photo.thumbnail_url, alt: photo.title, class: 'img img-responsive'), photo
.text
%p
= link_to photo.title, photo
%br/
%small
%i
by
= link_to photo.owner, photo.owner
= I18n.l(photo.created_at.to_date)

View File

@@ -12,15 +12,7 @@
%p= image_tag(@photo.fullsize_url, alt: @photo.title, class: 'img img-responsive')
.col-md-4
%p
- if can? :destroy, @photo
= link_to @photo, method: :delete,
data: { confirm: 'Are you sure?' }, class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-trash{ title: "Delete" }
- if can? :edit, @photo
= link_to edit_photo_path(@photo), class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-pencil{ title: "Edit" }
= render 'photos/actions', photo: @photo
%p
%strong Posted by:
= link_to @photo.owner, @photo.owner

View File

@@ -1,27 +1,12 @@
- if can?(:edit, planting) || can?(:destroy, planting)
- if can? :edit, planting
= link_to edit_planting_path(planting), class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-pencil{ title: "Edit" }
Edit
- 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')
- 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 can? :destroy, planting
= link_to planting, method: :delete,
data: { confirm: 'Are you sure?' }, class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-trash{ title: "Delete" }
Delete
- unless 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
- if can? :edit, planting
= link_to new_planting_harvest_path(planting), class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-leaf{ title: "Harvest" }
Harvest
- if can?(:edit, planting) && can?(:create, Photo)
= link_to new_photo_path(id: planting.id, type: 'planting'), class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-camera{ title: "Add photo" }
Add photo
= render 'shared/buttons/delete', path: planting

View File

@@ -8,7 +8,7 @@
.panel-body
.row
.col-xs-12.col-md-5
= link_to image_tag((planting.default_photo ? planting.default_photo.thumbnail_url : 'placeholder_150.png'),
= link_to image_tag(planting_image_path(planting),
alt: planting.crop_id, class: 'img img-responsive'),
planting
.col-xs-12.col-md-7
@@ -35,24 +35,6 @@
%dt Finish expected:
%dd= planting.finish_predicted_at if planting.finish_predicted_at.present?
%p= render 'plantings/progress', planting: planting, show_explanation: true
= link_to 'Details', planting_path(planting),
class: 'btn btn-default btn-xs'
- if can?(:edit, planting) && can?(:create, Harvest)
= link_to 'Harvest', new_planting_harvest_path(planting),
class: 'btn btn-default btn-xs'
- if can?(:edit, planting) && !planting.finished
= link_to "Mark as finished",
planting_path(planting, planting: { finished: 1 }),
method: :put,
class: 'btn btn-default btn-xs append-date'
- if can? :destroy, planting
= link_to planting, method: :delete,
data: { confirm: 'Are you sure?' },
class: 'btn btn-default btn-xs' do
%span.glyphicon.glyphicon-trash{ title: "Delete" }
.row
.col-md-12= render 'plantings/actions', planting: planting

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