mirror of
https://github.com/Growstuff/growstuff.git
synced 2026-05-25 09:19:15 -04:00
Compare commits
117 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c80685bf0d | ||
|
|
13d8a29773 | ||
|
|
dc09a6ea91 | ||
|
|
64a8cfb59f | ||
|
|
2f81d6c78d | ||
|
|
d5be92ac8b | ||
|
|
40d71ae070 | ||
|
|
2f45041f8c | ||
|
|
f9d4e1d6ae | ||
|
|
80203ad215 | ||
|
|
8c51d7bdd5 | ||
|
|
64e3b3b4d4 | ||
|
|
978523fd94 | ||
|
|
97f63d1147 | ||
|
|
1a9ff5eb4c | ||
|
|
72b1494db9 | ||
|
|
83bba916a4 | ||
|
|
64179850ff | ||
|
|
9cdf2e899f | ||
|
|
2eacf346a8 | ||
|
|
aab91e2fa9 | ||
|
|
2217d87b5a | ||
|
|
44b2251896 | ||
|
|
f5e20cd2d2 | ||
|
|
42de726405 | ||
|
|
65b4c7dbc1 | ||
|
|
6b6ed7e31c | ||
|
|
564901f93f | ||
|
|
f8127eeec3 | ||
|
|
33fb2408d6 | ||
|
|
ab56a3c6b3 | ||
|
|
ef4b4d0c46 | ||
|
|
44ba29137d | ||
|
|
ed2fcc2ada | ||
|
|
0b5c45d08f | ||
|
|
54c880a66c | ||
|
|
0699677d05 | ||
|
|
3c411f15b8 | ||
|
|
dcf5286275 | ||
|
|
7e1e2bef91 | ||
|
|
5cda14f87a | ||
|
|
88da0da616 | ||
|
|
a69afd87e7 | ||
|
|
57bfafccc7 | ||
|
|
24931381af | ||
|
|
742c7e30a9 | ||
|
|
2f3e368ede | ||
|
|
502a20cf10 | ||
|
|
b2cf022522 | ||
|
|
3d4598e4e1 | ||
|
|
94db28b3a9 | ||
|
|
767477df66 | ||
|
|
7f87ee1018 | ||
|
|
093a948922 | ||
|
|
be1553410f | ||
|
|
caf41e80c9 | ||
|
|
2eff7d6716 | ||
|
|
df5006c61c | ||
|
|
1e0565dd9b | ||
|
|
3453a648fa | ||
|
|
e8d9314cff | ||
|
|
92e56cfc1e | ||
|
|
3dc356eb29 | ||
|
|
56ed61b2b3 | ||
|
|
16ad5384d1 | ||
|
|
cf93489af7 | ||
|
|
86b9a3650b | ||
|
|
625a035f44 | ||
|
|
196d37dee9 | ||
|
|
6f613635d2 | ||
|
|
46267b2a1d | ||
|
|
8c8d549cb1 | ||
|
|
d9cc1dcae8 | ||
|
|
9db4736229 | ||
|
|
04a7c41f63 | ||
|
|
78b8be1fc2 | ||
|
|
b6e9539127 | ||
|
|
33276874a8 | ||
|
|
9adb3d1e4e | ||
|
|
3391f6c392 | ||
|
|
a13acbe087 | ||
|
|
0c8240d4e8 | ||
|
|
5ea7ae8af0 | ||
|
|
eb1b890eec | ||
|
|
4821bf3b07 | ||
|
|
b83db1d4e7 | ||
|
|
dea7ce241b | ||
|
|
8d166f1fe6 | ||
|
|
49253b59ee | ||
|
|
ca16b2c407 | ||
|
|
427a0187e1 | ||
|
|
b1096cd021 | ||
|
|
020d024e4b | ||
|
|
070a4605d0 | ||
|
|
1f8413bf3e | ||
|
|
59c3edcf82 | ||
|
|
1bf05f81ab | ||
|
|
e6e88fa0c7 | ||
|
|
308e834713 | ||
|
|
121deb4f48 | ||
|
|
4b65f28461 | ||
|
|
87708f1765 | ||
|
|
2cf335a064 | ||
|
|
b205f35399 | ||
|
|
a4c06207e3 | ||
|
|
580fac6aa1 | ||
|
|
4a696af9ba | ||
|
|
d2a060ad49 | ||
|
|
d898f926d5 | ||
|
|
49444edc61 | ||
|
|
a4c7de381e | ||
|
|
61408d7e4e | ||
|
|
9906036faf | ||
|
|
e009d9532a | ||
|
|
9f1c064900 | ||
|
|
8d3d8f3c91 | ||
|
|
0feed2d359 |
@@ -42,3 +42,4 @@ exclude_paths:
|
||||
- spec/
|
||||
- public/
|
||||
- app/assets/stylesheets/bootstrap-accessibility.css
|
||||
- app/assets/javascripts/bootstrap*
|
||||
|
||||
1
.esignore
Normal file
1
.esignore
Normal file
@@ -0,0 +1 @@
|
||||
app/assets/javascripts/bootstrap-accessibility.min.js
|
||||
11
.eslintrc.json
Normal file
11
.eslintrc.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "google",
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
},
|
||||
"rules": {
|
||||
"no-var": "off",
|
||||
"max-len": ["error", { "code": 120, "tabWidth": 4 }]
|
||||
}
|
||||
}
|
||||
@@ -8,3 +8,6 @@ scss:
|
||||
config_file: .scss-lint.yml
|
||||
eslint:
|
||||
config_file: .eslintrc
|
||||
ignore_file: .esignore
|
||||
jshint:
|
||||
enabled: false
|
||||
|
||||
@@ -46,7 +46,9 @@ PreCommit:
|
||||
required_executable: 'npm'
|
||||
HamlLint:
|
||||
enabled: true
|
||||
command: ['bundle', 'exec', 'haml-lint', 'app/views']
|
||||
include:
|
||||
- 'app/views/**'
|
||||
command: ['bundle', 'exec', 'haml-lint']
|
||||
JsonSyntax:
|
||||
enabled: true
|
||||
BundleOutdated:
|
||||
@@ -55,13 +57,13 @@ PreCommit:
|
||||
BundleAudit:
|
||||
enabled: true
|
||||
on_warn: warn
|
||||
JsHint:
|
||||
EsLint:
|
||||
enabled: true
|
||||
exclude:
|
||||
- 'app/assets/**'
|
||||
- 'spec/javascripts/support/vendor/**'
|
||||
- '**/bootstrap*'
|
||||
command: ['npm', 'run', 'jshint']
|
||||
command: ['./node_modules/.bin/eslint']
|
||||
required_executable: 'npm'
|
||||
ScssLint:
|
||||
enabled: true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# This configuration was generated by
|
||||
# `rubocop --auto-gen-config --no-offense-counts`
|
||||
# on 2017-12-06 11:20:15 +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
|
||||
@@ -39,7 +39,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'
|
||||
@@ -60,7 +59,6 @@ Style/AsciiComments:
|
||||
# SupportedStyles: nested, compact
|
||||
Style/ClassAndModuleChildren:
|
||||
Exclude:
|
||||
- 'app/controllers/admin/orders_controller.rb'
|
||||
- 'lib/actions/oauth_signup_action.rb'
|
||||
- 'lib/haml/filters/escaped_markdown.rb'
|
||||
|
||||
@@ -68,24 +66,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 +81,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
|
||||
|
||||
@@ -56,6 +56,7 @@ deploy:
|
||||
secure: "WrQxf0fEKkCdXrjcejurobOnNNz3he4dDwjBbToXbQTQNDObPp7NetJrLsfM8FiUFEeOuvhIHHiDQtMvY720zGGAGxDptvgFS+0QHCUqoTRZA/yFfUmHlG2jROXTzk5uVK0AE4k6Ion5kX8+mM0EnMT/7u+MTFiukrJctSiEXfg="
|
||||
on:
|
||||
repo: Growstuff/growstuff
|
||||
condition: "$RSPEC_TAG = elasticsearch"
|
||||
app:
|
||||
dev: growstuff-staging
|
||||
master: growstuff-prod
|
||||
|
||||
@@ -8,14 +8,15 @@ submit the change with your pull request.
|
||||
|
||||
## Committers
|
||||
|
||||
- Alex Bayley / [Skud](https://github.com/Skud)
|
||||
- Cesy / [cesy](https://github.com/cesy)
|
||||
- Miles Gould / [pozorvlak](https://github.com/pozorvlak)
|
||||
- Taylor Griffin / [tygriffin](https://github.com/tygriffin)
|
||||
- Mackenzie Morgan / [maco](https://github.com/maco)
|
||||
- Brenda Wallace / [br3nda](https://github.com/br3nda)
|
||||
|
||||
## Contributors
|
||||
|
||||
- Alex Bayley / [Skud](https://github.com/Skud)
|
||||
- Taylor Griffin / [tygriffin](https://github.com/tygriffin)
|
||||
- Joseph Caudle / [jcaudle](https://github.com/jcaudle)
|
||||
- Ricky Amianym / [amianym](https://github.com/amianym)
|
||||
- Juliet Kemp / [julietk](https://github.com/julietk)
|
||||
@@ -73,7 +74,6 @@ submit the change with your pull request.
|
||||
- Lucas Nogueira / [lucasnogueira](https://github.com/lucasnogueira)
|
||||
- Charley Lewittes / [ctlewitt](https://github.com/ctlewitt)
|
||||
- Kristine Nicole Polvoriza / [polveenomials](https://github.com/polveenomials)
|
||||
- Brenda Wallace / [br3nda](https://github.com/br3nda)
|
||||
- Jim Stallings / [jestallin](https://github.com/jestallin)
|
||||
- Alyssa Ransbury / [alran](https://github.com/alran)
|
||||
- Thomas Countz / [thomascountz](https://github.com/thomascountz)
|
||||
@@ -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
|
||||
|
||||
|
||||
9
Gemfile
9
Gemfile
@@ -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
|
||||
@@ -78,8 +77,7 @@ gem 'omniauth-facebook'
|
||||
gem 'omniauth-flickr', '>= 0.0.15'
|
||||
gem 'omniauth-twitter'
|
||||
|
||||
# For charting data
|
||||
gem 'd3-rails', '~> 3.5' # 4.* produces Error: <spyOn> : could not find an object to spy upon for linear() - see https://travis-ci.org/Growstuff/growstuff/jobs/204461482
|
||||
gem "chartkick"
|
||||
|
||||
# client for Elasticsearch. Elasticsearch is a flexible
|
||||
# and powerful, distributed, real-time search and analytics engine.
|
||||
@@ -126,7 +124,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
|
||||
@@ -158,3 +155,5 @@ end
|
||||
group :travis do
|
||||
gem 'platform-api'
|
||||
end
|
||||
gem 'loofah', '>= 2.2.1'
|
||||
gem 'rack-protection', '>= 2.0.1'
|
||||
|
||||
121
Gemfile.lock
121
Gemfile.lock
@@ -26,19 +26,12 @@ GEM
|
||||
addressable
|
||||
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)
|
||||
i18n
|
||||
activejob (4.2.10)
|
||||
activesupport (= 4.2.10)
|
||||
globalid (>= 0.3.0)
|
||||
activemerchant (1.75.0)
|
||||
activesupport (>= 3.2.14, < 6.x)
|
||||
builder (>= 2.1.2, < 4.0.0)
|
||||
i18n (>= 0.6.9)
|
||||
nokogiri (~> 1.4)
|
||||
activemodel (4.2.10)
|
||||
activesupport (= 4.2.10)
|
||||
builder (~> 3.1)
|
||||
@@ -57,15 +50,15 @@ GEM
|
||||
addressable (2.5.2)
|
||||
public_suffix (>= 2.0.2, < 4.0)
|
||||
arel (6.0.4)
|
||||
ast (2.3.0)
|
||||
autoprefixer-rails (7.2.3)
|
||||
ast (2.4.0)
|
||||
autoprefixer-rails (7.2.5)
|
||||
execjs
|
||||
bcrypt (3.1.11)
|
||||
better_errors (2.2.0)
|
||||
coderay (>= 1.0.0)
|
||||
erubis (>= 2.6.6)
|
||||
rack (>= 0.9.0)
|
||||
binding_of_caller (0.7.3)
|
||||
binding_of_caller (0.8.0)
|
||||
debug_inspector (>= 0.0.1)
|
||||
bluecloth (2.2.0)
|
||||
bonsai-elasticsearch-rails (0.2.0)
|
||||
@@ -81,24 +74,25 @@ GEM
|
||||
sass (>= 3.3.4)
|
||||
bootstrap_form (2.7.0)
|
||||
builder (3.2.3)
|
||||
bullet (5.7.0)
|
||||
bullet (5.7.2)
|
||||
activesupport (>= 3.0.0)
|
||||
uniform_notifier (~> 1.10.0)
|
||||
byebug (9.1.0)
|
||||
cancancan (2.1.2)
|
||||
capybara (2.16.1)
|
||||
uniform_notifier (~> 1.11.0)
|
||||
byebug (10.0.0)
|
||||
cancancan (2.1.3)
|
||||
capybara (2.17.0)
|
||||
addressable
|
||||
mini_mime (>= 0.1.3)
|
||||
nokogiri (>= 1.3.3)
|
||||
rack (>= 1.0.0)
|
||||
rack-test (>= 0.5.4)
|
||||
xpath (~> 2.0)
|
||||
xpath (>= 2.0, < 4.0)
|
||||
capybara-email (2.5.0)
|
||||
capybara (~> 2.4)
|
||||
mail
|
||||
capybara-screenshot (1.0.18)
|
||||
capybara (>= 1.0, < 3)
|
||||
launchy
|
||||
chartkick (2.2.5)
|
||||
childprocess (0.8.0)
|
||||
ffi (~> 1.0, >= 1.0.11)
|
||||
climate_control (0.2.0)
|
||||
@@ -143,12 +137,10 @@ GEM
|
||||
crass (1.0.3)
|
||||
csv_shaper (1.3.0)
|
||||
activesupport (>= 3.0.0)
|
||||
d3-rails (3.5.17)
|
||||
railties (>= 3.1)
|
||||
dalli (2.7.6)
|
||||
database_cleaner (1.6.2)
|
||||
debug_inspector (0.0.3)
|
||||
devise (4.3.0)
|
||||
devise (4.4.1)
|
||||
bcrypt (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
railties (>= 4.1.0, < 5.2)
|
||||
@@ -156,8 +148,7 @@ GEM
|
||||
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 (2.0.2)
|
||||
@@ -181,11 +172,11 @@ GEM
|
||||
factory_bot_rails (4.8.2)
|
||||
factory_bot (~> 4.8.2)
|
||||
railties (>= 3.0.0)
|
||||
faker (1.8.5)
|
||||
i18n (~> 0.9.1)
|
||||
faker (1.8.7)
|
||||
i18n (>= 0.7)
|
||||
faraday (0.12.2)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ffi (1.9.18)
|
||||
ffi (1.9.21)
|
||||
figaro (1.1.1)
|
||||
thor (~> 0.14)
|
||||
flickraw (0.9.9)
|
||||
@@ -203,10 +194,10 @@ GEM
|
||||
gravatar-ultimate (2.0.0)
|
||||
activesupport (>= 2.3.14)
|
||||
rack
|
||||
guard (2.14.1)
|
||||
guard (2.14.2)
|
||||
formatador (>= 0.2.4)
|
||||
listen (>= 2.7, < 4.0)
|
||||
lumberjack (~> 1.0)
|
||||
lumberjack (>= 1.0.12, < 2.0)
|
||||
nenv (~> 0.1)
|
||||
notiffany (~> 0.0)
|
||||
pry (>= 0.9.12)
|
||||
@@ -238,7 +229,7 @@ GEM
|
||||
rake (>= 10, < 13)
|
||||
rubocop (>= 0.49.0)
|
||||
sysexits (~> 1.1)
|
||||
hashie (3.5.6)
|
||||
hashie (3.5.7)
|
||||
heroics (0.0.24)
|
||||
erubis (~> 2.0)
|
||||
excon
|
||||
@@ -252,7 +243,7 @@ GEM
|
||||
ruby_parser (~> 3.5)
|
||||
httparty (0.15.6)
|
||||
multi_xml (>= 0.5.2)
|
||||
i18n (0.9.1)
|
||||
i18n (0.9.3)
|
||||
concurrent-ruby (~> 1.0)
|
||||
i18n-tasks (0.9.12)
|
||||
activesupport (>= 4.0.2)
|
||||
@@ -264,19 +255,19 @@ 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)
|
||||
jasmine (2.9.0)
|
||||
jasmine-core (>= 2.9.0, < 3.0.0)
|
||||
phantomjs
|
||||
rack (>= 1.2.1)
|
||||
rake
|
||||
jasmine-core (2.8.0)
|
||||
jasmine-core (2.99.0)
|
||||
jquery-rails (4.3.1)
|
||||
rails-dom-testing (>= 1, < 3)
|
||||
railties (>= 4.2.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
jquery-ui-rails (5.0.5)
|
||||
railties (>= 3.2.16)
|
||||
js-routes (1.4.2)
|
||||
js-routes (1.4.3)
|
||||
railties (>= 3.2)
|
||||
sprockets-rails
|
||||
json (2.1.0)
|
||||
@@ -297,19 +288,19 @@ GEM
|
||||
activerecord
|
||||
kaminari-core (= 1.1.1)
|
||||
kaminari-core (1.1.1)
|
||||
kgio (2.11.1)
|
||||
kgio (2.11.2)
|
||||
kramdown (1.16.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.4.1)
|
||||
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.1)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
lumberjack (1.0.12)
|
||||
@@ -323,14 +314,14 @@ GEM
|
||||
mimemagic (0.3.2)
|
||||
mini_mime (1.0.0)
|
||||
mini_portile2 (2.3.0)
|
||||
minitest (5.10.3)
|
||||
minitest (5.11.3)
|
||||
moneta (0.8.1)
|
||||
multi_json (1.11.3)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.0.0)
|
||||
nenv (0.3.0)
|
||||
newrelic_rpm (4.6.0.338)
|
||||
nokogiri (1.8.1)
|
||||
newrelic_rpm (4.8.0.341)
|
||||
nokogiri (1.8.2)
|
||||
mini_portile2 (~> 2.3.0)
|
||||
notiffany (0.1.1)
|
||||
nenv (~> 0.1)
|
||||
@@ -342,7 +333,7 @@ GEM
|
||||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
rack (>= 1.2, < 3)
|
||||
omniauth (1.7.1)
|
||||
omniauth (1.8.1)
|
||||
hashie (>= 3.4.6, < 3.6.0)
|
||||
rack (>= 1.6.2, < 3)
|
||||
omniauth-facebook (4.0.0)
|
||||
@@ -360,7 +351,7 @@ GEM
|
||||
omniauth-oauth (~> 1.1)
|
||||
rack
|
||||
orm_adapter (0.5.0)
|
||||
paperclip (5.1.0)
|
||||
paperclip (5.2.1)
|
||||
activemodel (>= 4.2.0)
|
||||
activesupport (>= 4.2.0)
|
||||
cocaine (~> 0.5.5)
|
||||
@@ -387,8 +378,8 @@ GEM
|
||||
public_suffix (3.0.1)
|
||||
quiet_assets (1.1.0)
|
||||
railties (>= 3.1, < 5.0)
|
||||
rack (1.6.8)
|
||||
rack-protection (2.0.0)
|
||||
rack (1.6.9)
|
||||
rack-protection (2.0.1)
|
||||
rack
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
@@ -403,13 +394,13 @@ GEM
|
||||
bundler (>= 1.3.0, < 2.0)
|
||||
railties (= 4.2.10)
|
||||
sprockets-rails
|
||||
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-deprecated_sanitizer (1.0.3)
|
||||
activesupport (>= 4.2.0.alpha)
|
||||
rails-dom-testing (1.0.8)
|
||||
activesupport (>= 4.2.0.beta, < 5.0)
|
||||
rails-dom-testing (1.0.9)
|
||||
activesupport (>= 4.2.0, < 5.0)
|
||||
nokogiri (~> 1.6)
|
||||
rails-deprecated_sanitizer (>= 1.0.1)
|
||||
rails-html-sanitizer (1.0.3)
|
||||
@@ -445,7 +436,7 @@ GEM
|
||||
activemodel (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
rspec-mocks (>= 2.99, < 4.0)
|
||||
rspec-core (3.7.0)
|
||||
rspec-core (3.7.1)
|
||||
rspec-support (~> 3.7.0)
|
||||
rspec-expectations (3.7.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
@@ -461,7 +452,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)
|
||||
@@ -475,7 +466,7 @@ GEM
|
||||
ruby_parser (3.10.1)
|
||||
sexp_processor (~> 4.9)
|
||||
rubyzip (1.2.1)
|
||||
sass (3.5.4)
|
||||
sass (3.5.5)
|
||||
sass-listen (~> 4.0.0)
|
||||
sass-listen (4.0.0)
|
||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||
@@ -486,12 +477,12 @@ GEM
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
sprockets-rails (>= 2.0, < 4.0)
|
||||
tilt (>= 1.1, < 3)
|
||||
selenium-webdriver (3.8.0)
|
||||
selenium-webdriver (3.9.0)
|
||||
childprocess (~> 0.5)
|
||||
rubyzip (~> 1.0)
|
||||
rubyzip (~> 1.2)
|
||||
sexp_processor (4.10.0)
|
||||
shellany (0.0.1)
|
||||
sidekiq (5.0.5)
|
||||
sidekiq (5.1.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
connection_pool (~> 2.2, >= 2.2.0)
|
||||
rack-protection (>= 1.5.0)
|
||||
@@ -523,15 +514,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.0.2)
|
||||
uglifier (4.1.5)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unicode-display_width (1.3.0)
|
||||
unicorn (5.3.1)
|
||||
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)
|
||||
@@ -543,17 +534,15 @@ GEM
|
||||
websocket-extensions (0.1.3)
|
||||
will_paginate (3.1.6)
|
||||
xmlrpc (0.3.0)
|
||||
xpath (2.1.0)
|
||||
nokogiri (~> 1.3)
|
||||
xpath (3.0.0)
|
||||
nokogiri (~> 1.8)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
active_median
|
||||
active_merchant-paypal-bogus-gateway
|
||||
active_utils
|
||||
activemerchant
|
||||
acts_as_paranoid (~> 0.5.0)
|
||||
better_errors (~> 2.2.0)
|
||||
binding_of_caller
|
||||
@@ -569,12 +558,12 @@ DEPENDENCIES
|
||||
capybara
|
||||
capybara-email
|
||||
capybara-screenshot
|
||||
chartkick
|
||||
codeclimate-test-reporter
|
||||
coffee-rails
|
||||
comfortable_mexican_sofa
|
||||
coveralls
|
||||
csv_shaper
|
||||
d3-rails (~> 3.5)
|
||||
dalli
|
||||
database_cleaner
|
||||
devise
|
||||
@@ -606,17 +595,19 @@ DEPENDENCIES
|
||||
kaminari
|
||||
leaflet-rails
|
||||
letter_opener
|
||||
loofah (>= 2.2.1)
|
||||
memcachier
|
||||
newrelic_rpm
|
||||
omniauth (~> 1.3)
|
||||
omniauth-facebook
|
||||
omniauth-flickr (>= 0.0.15)
|
||||
omniauth-twitter
|
||||
pg
|
||||
pg (< 1.0.0)
|
||||
platform-api
|
||||
poltergeist
|
||||
pry
|
||||
quiet_assets
|
||||
rack-protection (>= 2.0.1)
|
||||
rails (~> 4.2.8)
|
||||
rails-assets-leaflet.markercluster!
|
||||
rails_12factor
|
||||
@@ -638,9 +629,7 @@ DEPENDENCIES
|
||||
will_paginate
|
||||
xmlrpc
|
||||
|
||||
|
||||
RUBY VERSION
|
||||
ruby 2.4.1p111
|
||||
|
||||
BUNDLED WITH
|
||||
1.16.0
|
||||
1.16.1
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
||||
// GO AFTER THE REQUIRES BELOW.
|
||||
//
|
||||
//= require leaflet
|
||||
//= require leaflet.markercluster
|
||||
//= require js-routes
|
||||
//= require jquery
|
||||
//= require jquery_ujs
|
||||
//= require jquery-ui/autocomplete
|
||||
//= require bootstrap-sprockets
|
||||
//= require bootstrap-datepicker
|
||||
//= require_tree .
|
||||
// = require leaflet
|
||||
// = require leaflet.markercluster
|
||||
// = require js-routes
|
||||
// = require jquery
|
||||
// = require jquery_ujs
|
||||
// = require jquery-ui/autocomplete
|
||||
// = require bootstrap-sprockets
|
||||
// = require bootstrap-datepicker
|
||||
// = require_tree .
|
||||
|
||||
File diff suppressed because one or more lines are too long
2
app/assets/javascripts/charts.js
Normal file
2
app/assets/javascripts/charts.js
Normal file
@@ -0,0 +1,2 @@
|
||||
// = require Chart.bundle
|
||||
// = require chartkick
|
||||
39
app/assets/javascripts/crops.js.coffee
Normal file
39
app/assets/javascripts/crops.js.coffee
Normal 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()
|
||||
@@ -1,37 +1,27 @@
|
||||
//= require graphs/horizontal_bar_graph
|
||||
|
||||
if (document.getElementById("cropmap") !== null) {
|
||||
mapbox_map_id = "<%= Rails.env == 'test' ? 0 : Growstuff::Application.config.mapbox_map_id %>";
|
||||
mapbox_access_token = "<%= Rails.env == 'test' ? 0 : Growstuff::Application.config.mapbox_access_token %>";
|
||||
mapbox_base_url = "http://a.tiles.mapbox.com/v4/" + mapbox_map_id + "/{z}/{x}/{y}.png?access_token=" + mapbox_access_token;
|
||||
|
||||
L.Icon.Default.imagePath = '/assets'
|
||||
|
||||
cropmap = L.map('cropmap').setView([0.0, -0.0], 2);
|
||||
showCropMap(cropmap);
|
||||
}
|
||||
|
||||
function showCropMap(cropmap) {
|
||||
var mapbox_map_id = "<%= Rails.env == 'test' ? 0 : Growstuff::Application.config.mapbox_map_id %>";
|
||||
var mapbox_access_token = "<%= Rails.env == 'test' ? 0 : Growstuff::Application.config.mapbox_access_token %>";
|
||||
var mapbox_base_url = "http://a.tiles.mapbox.com/v4/" + mapbox_map_id + "/{z}/{x}/{y}.png?access_token=" + mapbox_access_token;
|
||||
|
||||
L.tileLayer(mapbox_base_url, {
|
||||
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors under <a href="http://www.openstreetmap.org/copyright">ODbL</a> | Map imagery © <a href="http://mapbox.com">Mapbox</a>',
|
||||
maxZoom: 18
|
||||
}).addTo(cropmap);
|
||||
markers = new L.MarkerClusterGroup({showCoverageOnHover: false, maxClusterRadius: 20 });
|
||||
var markers = new L.MarkerClusterGroup({showCoverageOnHover: false, maxClusterRadius: 20 });
|
||||
|
||||
things_to_map = location.pathname + '.json';
|
||||
var things_to_map = location.pathname + '.json';
|
||||
$.getJSON(things_to_map, function(crop) {
|
||||
$.each(crop.plantings, function(i, planting) {
|
||||
owner = planting.owner;
|
||||
var owner = planting.owner;
|
||||
if (owner.latitude && owner.longitude) {
|
||||
marker = new L.Marker(new L.LatLng(owner.latitude, owner.longitude));
|
||||
var marker = new L.Marker(new L.LatLng(owner.latitude, owner.longitude));
|
||||
|
||||
planting_url = "/plantings/" + planting.id;
|
||||
planting_link = "<a href='" + planting_url + "'>" + owner.login_name + "'s " + crop.name + "</a>";
|
||||
var planting_url = "/plantings/" + planting.id;
|
||||
var planting_link = "<a href='" + planting_url + "'>" + owner.login_name + "'s " + crop.name + "</a>";
|
||||
|
||||
where = "<p><i>" + owner.location + "</i></p>";
|
||||
var where = "<p><i>" + owner.location + "</i></p>";
|
||||
|
||||
details = "<p>";
|
||||
var details = "<p>";
|
||||
if (planting.quantity) {
|
||||
details = details + "Quantity: " + planting.quantity + "<br/>";
|
||||
}
|
||||
@@ -51,41 +41,17 @@ function showCropMap(cropmap) {
|
||||
cropmap.addLayer(markers);
|
||||
}
|
||||
|
||||
function plantingStats(crop) {
|
||||
var sunniness_counts = { 'empty': 0, 'sun': 0, 'semi-shade': 0, 'shade': 0 };
|
||||
$.each(crop.plantings, function(i, planting) {
|
||||
if (planting.sunniness) {
|
||||
sunniness_counts[planting.sunniness]++;
|
||||
} else {
|
||||
sunniness_counts['Empty']++;
|
||||
}
|
||||
$(document).ready(function() {
|
||||
|
||||
if (document.getElementById("cropmap") !== null) {
|
||||
|
||||
L.Icon.Default.imagePath = '/assets';
|
||||
|
||||
var cropmap = L.map('cropmap').setView([0.0, -0.0], 2);
|
||||
showCropMap(cropmap);
|
||||
}
|
||||
|
||||
$('.btn.toggle.crop-hierarchy').click(function () {
|
||||
$('.toggle.crop-hierarchy').toggleClass('hide');
|
||||
});
|
||||
return [
|
||||
{name: 'Empty', value: sunniness_counts['empty']},
|
||||
{name: 'Sun', value: sunniness_counts['sun']},
|
||||
{name: 'Semi-shade', value: sunniness_counts['semi-shade']},
|
||||
{name: 'Shade', value: sunniness_counts['shade']}
|
||||
];
|
||||
}
|
||||
|
||||
if ($("#sunchart")[0] !== null) {
|
||||
var HorizontalBarGraph = growstuff.HorizontalBarGraph;
|
||||
$.getJSON(location.pathname + '.json', function (crop) {
|
||||
data = {
|
||||
bars: plantingStats(crop),
|
||||
bar_color: 'steelblue',
|
||||
width: {size: 300, scale: 'linear'},
|
||||
height: {size: 100, scale: 'ordinal'},
|
||||
//left is used to shift the bars over so that there is
|
||||
//room for the labels
|
||||
margin: {top: 0, right: 0, bottom: 0, left: 100}
|
||||
};
|
||||
|
||||
var graph = new HorizontalBarGraph(data);
|
||||
graph.render(d3.select($('#sunchart')[0]));
|
||||
});
|
||||
}
|
||||
|
||||
$('.btn.toggle.crop-hierarchy').click(function () {
|
||||
$('.toggle.crop-hierarchy').toggleClass('hide');
|
||||
});
|
||||
});
|
||||
19
app/assets/javascripts/finish_seed.js.coffee
Normal file
19
app/assets/javascripts/finish_seed.js.coffee
Normal 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('')
|
||||
)
|
||||
@@ -1,50 +0,0 @@
|
||||
//= require graphs/width_scale
|
||||
//= require graphs/height_scale
|
||||
|
||||
(function(){
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
This represents bars for a bar graph.
|
||||
Currently these are used for HorizontalBarGraph.
|
||||
*/
|
||||
|
||||
var growstuff = (window.growstuff = window.growstuff || {});
|
||||
var WidthScale = growstuff.WidthScale;
|
||||
var HeightScale = growstuff.HeightScale;
|
||||
|
||||
function BarGroup(data) {
|
||||
this._data = data;
|
||||
}
|
||||
|
||||
BarGroup.prototype.render = function(root){
|
||||
|
||||
var data = this._data;
|
||||
var bars = this._data.bars;
|
||||
var widthScale = new WidthScale(data).render();
|
||||
var heightScale = new HeightScale(data).render();
|
||||
|
||||
return root.append('g')
|
||||
.attr("class", "bar")
|
||||
.selectAll("rect")
|
||||
.data(bars.map(function(bar) { return bar.value; }))
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("y", function(d, i){
|
||||
return heightScale(i);
|
||||
|
||||
})
|
||||
.attr("height", heightScale.rangeBand())
|
||||
.attr("fill", data.bar_color)
|
||||
.attr("width", function(d){
|
||||
return widthScale(d);
|
||||
})
|
||||
.append("title")
|
||||
.text(function(d){
|
||||
return 'This value is ' + d + '.';
|
||||
});
|
||||
};
|
||||
|
||||
growstuff.BarGroup = BarGroup;
|
||||
|
||||
}());
|
||||
@@ -1,40 +0,0 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
This file draws the labels to the left of each bar.
|
||||
*/
|
||||
|
||||
var growstuff = (window.growstuff = window.growstuff || {});
|
||||
|
||||
function BarLabelGroup(data) {
|
||||
this._data = data;
|
||||
}
|
||||
|
||||
BarLabelGroup.prototype.render = function(d3){
|
||||
var bars = this._data.bars;
|
||||
//vvcopy pasta from spike vv -- this is a good candidate for refactor
|
||||
var barHeight = 40;
|
||||
|
||||
return d3.append('g')
|
||||
.attr("class", "bar-label")
|
||||
.selectAll("text")
|
||||
.data(bars.map(function(bar){ return bar.name;}))
|
||||
.enter()
|
||||
.append("text")
|
||||
.attr('x', -80)
|
||||
.attr('y', function(d, i){
|
||||
//shrink the margin between each label to give them an even spread with
|
||||
//bars
|
||||
var barLabelSpread = 2/3;
|
||||
//move them downward to line up with bars
|
||||
var barLabelTopEdge = 17;
|
||||
return i * barHeight * (barLabelSpread) + barLabelTopEdge;
|
||||
})
|
||||
.text(function(d){return d;});
|
||||
|
||||
};
|
||||
|
||||
growstuff.BarLabelGroup = BarLabelGroup;
|
||||
|
||||
}());
|
||||
@@ -1,29 +0,0 @@
|
||||
//=require d3
|
||||
|
||||
/*
|
||||
Height Scale is used to map the number of bars to the display size of
|
||||
the svg
|
||||
*/
|
||||
|
||||
(function(){
|
||||
'use strict';
|
||||
|
||||
var growstuff = (window.growstuff = window.growstuff || {});
|
||||
|
||||
function HeightScale(data){
|
||||
this._data = data;
|
||||
}
|
||||
|
||||
HeightScale.prototype.render = function(){
|
||||
var data = this._data;
|
||||
var scaleType = data.height.scale;
|
||||
var axisSize = data.height.size;
|
||||
|
||||
return d3.scale[scaleType]()
|
||||
.domain(d3.range(data.bars.length))
|
||||
.rangeRoundBands([0, data.height.size], 0.05, 0);
|
||||
};
|
||||
|
||||
growstuff.HeightScale = HeightScale;
|
||||
|
||||
}());
|
||||
@@ -1,51 +0,0 @@
|
||||
//= require d3
|
||||
//= require graphs/bar_group
|
||||
//= require graphs/bar_label_group
|
||||
|
||||
/*
|
||||
Horizontal Bar Graph represents sum total of the graph including all of the parts:
|
||||
Bars
|
||||
Bar Labels
|
||||
|
||||
The main dimensions of the graph are rendered here.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var growstuff = (window.growstuff = window.growstuff || {});
|
||||
var BarGroup = growstuff.BarGroup;
|
||||
var BarLabelGroup = growstuff.BarLabelGroup;
|
||||
|
||||
function HorizontalBarGraph(data) {
|
||||
this._data = data;
|
||||
this._d3 = d3;
|
||||
}
|
||||
|
||||
HorizontalBarGraph.prototype.render = function(root) {
|
||||
var bars = this._data.bars;
|
||||
var width = this._data.width;
|
||||
var height = this._data.height;
|
||||
|
||||
var barLabelGroup = new BarLabelGroup(this._data);
|
||||
var margin = this._data.margin;
|
||||
|
||||
var barGroup = new BarGroup(this._data);
|
||||
|
||||
var svg = root
|
||||
.append("svg")
|
||||
.attr("width", width.size + margin.left + margin.right)
|
||||
.attr("height", height.size + margin.top + margin.bottom)
|
||||
.append("g")
|
||||
.attr("class","bar-graph")
|
||||
.attr("transform","translate(" + margin.left + "," + margin.top + ")");
|
||||
|
||||
|
||||
barGroup.render(svg);
|
||||
barLabelGroup.render(svg);
|
||||
|
||||
return svg;
|
||||
};
|
||||
|
||||
growstuff.HorizontalBarGraph = HorizontalBarGraph;
|
||||
}());
|
||||
@@ -1,33 +0,0 @@
|
||||
//=require d3
|
||||
|
||||
/*
|
||||
Width scale is used to map the value for the length of each bar
|
||||
to the display size of the svg
|
||||
*/
|
||||
|
||||
(function(){
|
||||
'use strict';
|
||||
|
||||
var growstuff = (window.growstuff = window.growstuff || {});
|
||||
|
||||
function WidthScale (data){
|
||||
this._data = data;
|
||||
}
|
||||
|
||||
WidthScale.prototype.render = function() {
|
||||
var data = this._data;
|
||||
var scaleType = data.width.scale;
|
||||
var axisSize = data.width.size;
|
||||
|
||||
return d3.scale[scaleType]()
|
||||
.domain([0, this.getMaxValue()])
|
||||
.range([0, axisSize]);
|
||||
};
|
||||
|
||||
WidthScale.prototype.getMaxValue = function(){
|
||||
return d3.max(this._data.bars.map(function(bar) { return bar.value; }));
|
||||
};
|
||||
|
||||
growstuff.WidthScale = WidthScale;
|
||||
|
||||
}());
|
||||
@@ -1,25 +1,24 @@
|
||||
if (document.getElementById("membermap") !== null) {
|
||||
mapbox_map_id = "<%= Rails.env == 'test' ? 0 : Growstuff::Application.config.mapbox_map_id %>";
|
||||
mapbox_access_token = "<%= Rails.env == 'test' ? 0 : Growstuff::Application.config.mapbox_access_token %>";
|
||||
mapbox_base_url = "http://a.tiles.mapbox.com/v4/" + mapbox_map_id + "/{z}/{x}/{y}.png?access_token=" + mapbox_access_token;
|
||||
|
||||
L.Icon.Default.imagePath = '/assets'
|
||||
var mapbox_map_id = "<%= Rails.env == 'test' ? 0 : Growstuff::Application.config.mapbox_map_id %>";
|
||||
var mapbox_access_token = "<%= Rails.env == 'test' ? 0 : Growstuff::Application.config.mapbox_access_token %>";
|
||||
var mapbox_base_url = "http://a.tiles.mapbox.com/v4/" + mapbox_map_id + "/{z}/{x}/{y}.png?access_token=" + mapbox_access_token;
|
||||
|
||||
L.Icon.Default.imagePath = '/assets';
|
||||
|
||||
$.getJSON(location.pathname + '.json', function(member) {
|
||||
if (member.latitude && member.longitude) {
|
||||
membermap = L.map('membermap').setView([member.latitude, member.longitude], 4);
|
||||
var membermap = L.map('membermap').setView([member.latitude, member.longitude], 4);
|
||||
|
||||
L.tileLayer(mapbox_base_url, {
|
||||
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors under <a href="http://www.openstreetmap.org/copyright">ODbL</a> | Map imagery © <a href="http://mapbox.com">Mapbox</a>',
|
||||
maxZoom: 18
|
||||
}).addTo(membermap);
|
||||
marker = new L.Marker(new L.LatLng(member.latitude, member.longitude));
|
||||
var marker = new L.Marker(new L.LatLng(member.latitude, member.longitude));
|
||||
|
||||
member_url = "/members/" + member.slug;
|
||||
member_link = "<a href='" + member_url + "'>" + member.login_name + "</a>";
|
||||
var member_url = "/members/" + member.slug;
|
||||
var member_link = "<a href='" + member_url + "'>" + member.login_name + "</a>";
|
||||
|
||||
where = "<p><i>" + member.location + "</i></p>";
|
||||
var where = "<p><i>" + member.location + "</i></p>";
|
||||
|
||||
marker.bindPopup(member_link + where).openPopup();
|
||||
marker.addTo(membermap);
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
$(document).ready(function () {
|
||||
$(document).ready(function() {
|
||||
$('.post-like').show();
|
||||
|
||||
$('.post-like').on('ajax:success', function(event, data) {
|
||||
var like_control = $('#post-' + data.id + ' .post-like');
|
||||
var likeControl = $('#post-' + data.id + ' .post-like');
|
||||
|
||||
$('#post-' + data.id + ' .like-count').text(data.description);
|
||||
if (data.liked_by_member) {
|
||||
like_control.data("method", "delete");
|
||||
like_control.attr("href", data.url);
|
||||
like_control.text("Unlike");
|
||||
likeControl.data('method', 'delete');
|
||||
likeControl.attr('href', data.url);
|
||||
likeControl.text('Unlike');
|
||||
} else {
|
||||
like_control.data("method", "post");
|
||||
like_control.attr("href", '/likes.json?post_id=' + data.id);
|
||||
like_control.text("Like");
|
||||
likeControl.data('method', 'post');
|
||||
likeControl.attr('href', '/likes.json?post_id=' + data.id);
|
||||
likeControl.text('Like');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -5,3 +5,4 @@
|
||||
@import 'custom_bootstrap/custom_bootstrap'
|
||||
@import 'overrides'
|
||||
@import 'graphs'
|
||||
@import 'predictions'
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -13,6 +13,7 @@ $blue: #2f4365
|
||||
$red: #8e4d43
|
||||
$orange: #ffa500
|
||||
$yellow: #b2935c
|
||||
$white: #ffffff
|
||||
|
||||
$body-bg: $beige
|
||||
$text-color: $brown
|
||||
|
||||
@@ -3,37 +3,18 @@
|
||||
@import "custom_bootstrap/variables"
|
||||
// this padding needs to be done before the responsive stuff is imported
|
||||
body
|
||||
// modifying this for our promotional banner. can be replaced after if
|
||||
// needed.
|
||||
// padding-top: $navbar-height + 15px
|
||||
padding-top: $navbar-height
|
||||
|
||||
|
||||
//@import "bootstrap/responsive"
|
||||
|
||||
// Font Awesome
|
||||
@import "font-awesome-sprockets"
|
||||
@import "font-awesome"
|
||||
|
||||
// Glyphicons
|
||||
//@import "bootstrap/glyphicons"
|
||||
|
||||
|
||||
.list-inline > li.first
|
||||
padding-left: 0px
|
||||
|
||||
h2
|
||||
font-size: 150%
|
||||
|
||||
|
||||
//#subtitle
|
||||
// color: lighten($brown, 30%)
|
||||
// font-style: italic
|
||||
// font-weight: normal
|
||||
// margin-top: 0px
|
||||
// padding-left: 1em
|
||||
// padding-top: 0px
|
||||
|
||||
h3
|
||||
font-size: 120%
|
||||
|
||||
@@ -113,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
|
||||
@@ -273,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%)
|
||||
@@ -345,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
|
||||
|
||||
11
app/assets/stylesheets/predictions.sass
Normal file
11
app/assets/stylesheets/predictions.sass
Normal file
@@ -0,0 +1,11 @@
|
||||
.predictions
|
||||
.metric
|
||||
height: 180px
|
||||
border: 1px solid lighten($green, 20%)
|
||||
background: $white
|
||||
margin: 4px
|
||||
strong
|
||||
font-size: 250%
|
||||
font-align: center
|
||||
h3
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
30
app/controllers/charts/crops_controller.rb
Normal file
30
app/controllers/charts/crops_controller.rb
Normal 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
|
||||
16
app/controllers/charts/gardens_controller.rb
Normal file
16
app/controllers/charts/gardens_controller.rb
Normal 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
|
||||
@@ -51,9 +51,9 @@ 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_to do |format|
|
||||
format.html # show.html.haml
|
||||
format.html
|
||||
format.json { render json: @crop.to_json(crop_json_fields) }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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
|
||||
@@ -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: Growstuff::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: Growstuff::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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,6 +55,7 @@ class PlantingsController < ApplicationController
|
||||
def create
|
||||
@planting = Planting.new(planting_params)
|
||||
@planting.owner = current_member
|
||||
@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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
39
app/helpers/photos_helper.rb
Normal file
39
app/helpers/photos_helper.rb
Normal file
@@ -0,0 +1,39 @@
|
||||
module PhotosHelper
|
||||
def crop_image_path(crop)
|
||||
if crop.default_photo.present?
|
||||
crop.default_photo.thumbnail_url
|
||||
else
|
||||
default_image
|
||||
end
|
||||
end
|
||||
|
||||
def planting_image_path(planting)
|
||||
if planting.photos.present?
|
||||
planting.photos.first.thumbnail_url
|
||||
else
|
||||
default_image
|
||||
end
|
||||
end
|
||||
|
||||
def harvest_image_path(harvest)
|
||||
if harvest.photos.present?
|
||||
harvest.photos.first.thumbnail_url
|
||||
else
|
||||
default_image
|
||||
end
|
||||
end
|
||||
|
||||
def seed_image_path(seed)
|
||||
if seed.default_photo
|
||||
seed.default_photo.thumbnail_url
|
||||
else
|
||||
default_image
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def default_image
|
||||
'placeholder_150.png'
|
||||
end
|
||||
end
|
||||
@@ -37,17 +37,20 @@ class Notifier < ActionMailer::Base
|
||||
end
|
||||
|
||||
def new_crop_request(member, request)
|
||||
@member, @request = member, request
|
||||
@member = member
|
||||
@request = request
|
||||
mail(to: @member.email, subject: "#{@request.requester.login_name} has requested #{@request.name} as a new crop")
|
||||
end
|
||||
|
||||
def crop_request_approved(member, crop)
|
||||
@member, @crop = member, crop
|
||||
@member = member
|
||||
@crop = crop
|
||||
mail(to: @member.email, subject: "#{crop.name.capitalize} has been approved")
|
||||
end
|
||||
|
||||
def crop_request_rejected(member, crop)
|
||||
@member, @crop = member, crop
|
||||
@member = member
|
||||
@crop = crop
|
||||
mail(to: @member.email, subject: "#{crop.name.capitalize} has been rejected")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,17 +15,18 @@ class Ability
|
||||
can :view_follows, Member
|
||||
can :view_followers, Member
|
||||
|
||||
# Everyone can see the charts
|
||||
can :timeline, Garden
|
||||
can :sunniness, Crop
|
||||
can :planted_from, Crop
|
||||
can :harvested_for, Crop
|
||||
|
||||
# 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
|
||||
@@ -110,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
|
||||
@@ -142,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|
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
class Account < ActiveRecord::Base
|
||||
belongs_to :member
|
||||
belongs_to :account_type
|
||||
|
||||
validates :member_id, uniqueness: {
|
||||
message: 'already has account details associated with it'
|
||||
}
|
||||
|
||||
before_create do |account|
|
||||
unless account.account_type
|
||||
account.account_type = AccountType.find_or_create_by(name:
|
||||
Growstuff::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
|
||||
@@ -1,13 +0,0 @@
|
||||
class AccountType < ActiveRecord::Base
|
||||
#
|
||||
# Relationships
|
||||
has_many :products
|
||||
|
||||
#
|
||||
# Validations
|
||||
validates :name, presence: true, uniqueness: true
|
||||
|
||||
def to_s
|
||||
name
|
||||
end
|
||||
end
|
||||
12
app/models/concerns/finishable.rb
Normal file
12
app/models/concerns/finishable.rb
Normal 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
|
||||
@@ -46,7 +46,7 @@ class CsvImporter
|
||||
|
||||
names_to_add.each do |name|
|
||||
sciname = ScientificName.find_by(name: name, crop: @crop)
|
||||
sciname = ScientificName.create!(name: name, crop: @crop, creator: cropbot) unless sciname
|
||||
sciname ||= ScientificName.create!(name: name, crop: @crop, creator: cropbot)
|
||||
@crop.scientific_names << sciname
|
||||
end
|
||||
end
|
||||
@@ -56,15 +56,15 @@ class CsvImporter
|
||||
return if alternate_names.blank?
|
||||
alternate_names.split(/,\s*/).each do |name|
|
||||
altname = AlternateName.find_by(name: name, crop: @crop)
|
||||
altname = AlternateName.create! name: name, crop: @crop, creator: cropbot unless altname
|
||||
altname ||= AlternateName.create! name: name, crop: @crop, creator: cropbot
|
||||
@crop.alternate_names << altname
|
||||
end
|
||||
end
|
||||
|
||||
def cropbot
|
||||
@cropbot = Member.find_by!(login_name: 'cropbot') unless @cropbot
|
||||
@cropbot ||= Member.find_by!(login_name: 'cropbot')
|
||||
@cropbot
|
||||
rescue
|
||||
rescue StandardError
|
||||
raise "cropbot account not found: run rake db:seed"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -40,6 +40,13 @@ class Harvest < ActiveRecord::Base
|
||||
##
|
||||
## 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
|
||||
|
||||
@@ -7,7 +7,7 @@ class Member < ActiveRecord::Base
|
||||
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 < ActiveRecord::Base
|
||||
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
|
||||
@@ -79,11 +76,9 @@ class Member < ActiveRecord::Base
|
||||
after_save :update_newsletter_subscription
|
||||
|
||||
# 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
|
||||
after_create { |member| Garden.create(name: "Garden", owner_id: member.id) }
|
||||
after_create { |member| Account.find_or_create_by(member_id: member.id) }
|
||||
|
||||
# allow login via either login_name or email address
|
||||
def self.find_first_by_auth_conditions(warden_conditions)
|
||||
@@ -101,34 +96,6 @@ class Member < ActiveRecord::Base
|
||||
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
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
class Order < ActiveRecord::Base
|
||||
#
|
||||
# Relationships
|
||||
belongs_to :member, with_deleted: true
|
||||
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
|
||||
@@ -1,12 +0,0 @@
|
||||
class OrderItem < ActiveRecord::Base
|
||||
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
|
||||
@@ -27,7 +27,8 @@ class Photo < ActiveRecord::Base
|
||||
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 < ActiveRecord::Base
|
||||
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
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
class Planting < ActiveRecord::Base
|
||||
extend FriendlyId
|
||||
include PhotoCapable
|
||||
include Finishable
|
||||
friendly_id :planting_slug, use: %i(slugged finders)
|
||||
|
||||
# Constants
|
||||
SUNNINESS_VALUES = %w(sun semi-shade shade)
|
||||
SUNNINESS_VALUES = %w(sun semi-shade shade).freeze
|
||||
PLANTED_FROM_VALUES = [
|
||||
'seed', 'seedling', 'cutting', 'root division', 'runner',
|
||||
'bulb', 'root/tuber', 'bare root plant', 'advanced plant',
|
||||
'graft', 'layering'
|
||||
]
|
||||
].freeze
|
||||
|
||||
##
|
||||
## Triggers
|
||||
@@ -20,11 +21,15 @@ class Planting < ActiveRecord::Base
|
||||
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 {
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
class Product < ActiveRecord::Base
|
||||
#
|
||||
# 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
|
||||
@@ -1,6 +1,7 @@
|
||||
class Seed < ActiveRecord::Base
|
||||
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 < ActiveRecord::Base
|
||||
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 < ActiveRecord::Base
|
||||
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 < ActiveRecord::Base
|
||||
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
|
||||
|
||||
@@ -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'
|
||||
@@ -1,7 +0,0 @@
|
||||
- content_for :title, "Editing account type"
|
||||
|
||||
= render 'form'
|
||||
|
||||
= link_to 'Show', @account_type
|
||||
\|
|
||||
= link_to 'Back', account_types_path
|
||||
@@ -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
|
||||
@@ -1,5 +0,0 @@
|
||||
- content_for :title, "New account type"
|
||||
|
||||
= render 'form'
|
||||
|
||||
= link_to 'Back', account_types_path
|
||||
@@ -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
|
||||
@@ -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'
|
||||
@@ -1,7 +0,0 @@
|
||||
- content_for :title, "Editing account"
|
||||
|
||||
= render 'form'
|
||||
|
||||
= link_to 'Show', @account
|
||||
\|
|
||||
= link_to 'Back', accounts_path
|
||||
@@ -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
|
||||
@@ -1,5 +0,0 @@
|
||||
- content_for :title, "New account"
|
||||
|
||||
= render 'form'
|
||||
|
||||
= link_to 'Back', accounts_path
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
@@ -11,5 +11,5 @@
|
||||
%th
|
||||
- @members.each do |member|
|
||||
%tr
|
||||
%td= ember.login_name
|
||||
%td= member.login_name
|
||||
%td= member.email
|
||||
|
||||
@@ -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'
|
||||
@@ -1,3 +0,0 @@
|
||||
- content_for :title, 'Admin Orders'
|
||||
|
||||
= render "admin/orders/searchform"
|
||||
@@ -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'
|
||||
8
app/views/crops/_actions.html.haml
Normal file
8
app/views/crops/_actions.html.haml
Normal 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'
|
||||
@@ -51,7 +51,8 @@
|
||||
.form-group
|
||||
= f.label :parent_id, 'Parent crop', class: 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= collection_select(:crop, :parent_id, Crop.all, :id, :name, { include_blank: true }, class: 'form-control')
|
||||
= collection_select(:crop, :parent_id, Crop.all.order(:name), :id, :name,
|
||||
{ include_blank: true }, class: 'form-control')
|
||||
%span.help-block Optional. For setting up crop hierarchies for varieties etc.
|
||||
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,29 +1,35 @@
|
||||
- unless crop.perennial.nil?
|
||||
%p
|
||||
#{crop.name} is
|
||||
- if crop.perennial == true
|
||||
= link_to 'https://en.wikipedia.org/wiki/Annual_vs._perennial_plant_evolution' do
|
||||
a perennial crop
|
||||
(living more than two years)
|
||||
- elsif crop.perennial == false
|
||||
= link_to 'https://en.wikipedia.org/wiki/Annual_vs._perennial_plant_evolution' do
|
||||
an annual crop
|
||||
(living and reproducing in a single year or less)
|
||||
.predictions
|
||||
- unless crop.perennial.nil?
|
||||
.row
|
||||
.col-md-12
|
||||
%p
|
||||
#{crop.name} is
|
||||
- if crop.perennial == true
|
||||
= link_to 'https://en.wikipedia.org/wiki/Annual_vs._perennial_plant_evolution' do
|
||||
a perennial crop
|
||||
(living more than two years)
|
||||
- elsif crop.perennial == false
|
||||
= link_to 'https://en.wikipedia.org/wiki/Annual_vs._perennial_plant_evolution' do
|
||||
an annual crop
|
||||
(living and reproducing in a single year or less)
|
||||
|
||||
- if crop.annual? && crop.median_lifespan.present?
|
||||
%p
|
||||
Median lifespan of #{crop.name} plants is
|
||||
%strong= crop.median_lifespan
|
||||
days
|
||||
.row
|
||||
- if crop.annual? && crop.median_lifespan.present?
|
||||
.metric.col-md-3.col-xs-5
|
||||
%h3 Median lifespan
|
||||
%strong= crop.median_lifespan
|
||||
%span days
|
||||
|
||||
- if crop.median_days_to_first_harvest.present?
|
||||
%p
|
||||
First harvest expected
|
||||
%strong= crop.median_days_to_first_harvest
|
||||
days after planting
|
||||
- if crop.median_days_to_first_harvest.present?
|
||||
.metric.col-md-3.col-xs-5
|
||||
%h3 First harvest expected
|
||||
%strong= crop.median_days_to_first_harvest
|
||||
%span days
|
||||
after planting
|
||||
|
||||
- if crop.annual? && crop.median_days_to_last_harvest.present?
|
||||
%p
|
||||
Last harvest expected
|
||||
%strong= crop.median_days_to_last_harvest
|
||||
days after planting
|
||||
- if crop.annual? && crop.median_days_to_last_harvest.present?
|
||||
.metric.col-md-3.col-xs-5
|
||||
%h3 Last harvest expected
|
||||
%strong= crop.median_days_to_last_harvest
|
||||
%span days
|
||||
after planting
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.thumbnail
|
||||
.crop-thumbnail
|
||||
- if crop
|
||||
- cache cache_key_for(Crop, crop.id) do
|
||||
- cache cache_key_for(Crop, crop.id) do
|
||||
.thumbnail
|
||||
.crop-thumbnail
|
||||
- if crop
|
||||
= link_to image_tag((crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png'),
|
||||
alt: crop.name, class: 'img'),
|
||||
crop
|
||||
|
||||
@@ -8,52 +8,62 @@
|
||||
= 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
|
||||
- if member_signed_in?
|
||||
= display_seed_availability(@current_member, @crop)
|
||||
= link_to "View your seeds", seeds_by_owner_path(owner: current_member.slug)
|
||||
.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 Predictions
|
||||
= render 'predictions', crop: @crop
|
||||
%h2
|
||||
- if !@crop.plantings.empty?
|
||||
= @crop.name.titleize
|
||||
has been planted
|
||||
= pluralize(@crop.plantings.size, "time")
|
||||
by #{ENV['GROWSTUFF_SITE_NAME']} members.
|
||||
- else
|
||||
Nobody is growing this yet. You could be the first!
|
||||
|
||||
%p= render 'crops/photos', crop: @crop
|
||||
|
||||
%h2
|
||||
- if !@crop.plantings.empty?
|
||||
= @crop.name.titleize
|
||||
has been planted
|
||||
= pluralize(@crop.plantings.size, "time")
|
||||
by #{ENV['GROWSTUFF_SITE_NAME']} members.
|
||||
- else
|
||||
Nobody is growing this yet. You could be the first!
|
||||
.row
|
||||
.col-md-12
|
||||
%h2 Predictions
|
||||
= render 'predictions', crop: @crop
|
||||
|
||||
%h2
|
||||
Sunniness Chart
|
||||
.row
|
||||
.col-md-12
|
||||
%h2 Photos
|
||||
%p= render 'crops/photos', crop: @crop
|
||||
.row
|
||||
.col-md-3
|
||||
%h2 Sunniness
|
||||
= pie_chart crop_sunniness_path(@crop), legend: "bottom"
|
||||
|
||||
#sunchart
|
||||
.col-md-3
|
||||
%h2 Planted from
|
||||
= pie_chart crop_planted_from_path(@crop), legend: "bottom"
|
||||
.col-md-3
|
||||
%h2 Harvested for
|
||||
= pie_chart crop_harvested_for_path(@crop), legend: "bottom"
|
||||
|
||||
%h2
|
||||
Crop Map
|
||||
%p
|
||||
Only plantings by members who have set their locations are shown on this map.
|
||||
- if current_member && current_member.location.blank?
|
||||
= link_to "Set your location.", edit_member_registration_path
|
||||
|
||||
#cropmap
|
||||
.row
|
||||
.col-md-12
|
||||
%h2 Crop Map
|
||||
%p
|
||||
Only plantings by members who have set their locations are shown on this map.
|
||||
- if current_member && current_member.location.blank?
|
||||
= link_to "Set your location.", edit_member_registration_path
|
||||
#cropmap
|
||||
|
||||
%a{ name: 'posts' }
|
||||
%h2 What people are saying about #{@crop.name.pluralize}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -9,9 +9,15 @@
|
||||
= tag("meta", property: "og:type", content: "website")
|
||||
= 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"
|
||||
= 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
|
||||
@@ -21,18 +27,23 @@
|
||||
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 What's planted here?
|
||||
%h3 Garden timeline
|
||||
.row
|
||||
.col-md-12= timeline garden_timeline_path(@garden), adapter: "google"
|
||||
|
||||
%h3 Current plantings in garden
|
||||
.row
|
||||
- if @current_plantings.size.positive?
|
||||
- @current_plantings.each do |planting|
|
||||
|
||||
6
app/views/harvests/_actions.html.haml
Normal file
6
app/views/harvests/_actions.html.haml
Normal 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)
|
||||
@@ -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
|
||||
|
||||
9
app/views/harvests/_image_with_popover.haml
Normal file
9
app/views/harvests/_image_with_popover.haml
Normal 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
|
||||
11
app/views/harvests/_list.html.haml
Normal file
11
app/views/harvests/_list.html.haml
Normal 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
|
||||
3
app/views/harvests/_popover.html.haml
Normal file
3
app/views/harvests/_popover.html.haml
Normal file
@@ -0,0 +1,3 @@
|
||||
%p
|
||||
%small
|
||||
= harvest.harvested_at
|
||||
@@ -7,3 +7,4 @@
|
||||
.harvestinfo
|
||||
.harvest-name
|
||||
= link_to harvest, harvest
|
||||
= I18n.l(harvest.harvested_at.to_date)
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
3
app/views/home/_harvests.html.haml
Normal file
3
app/views/home/_harvests.html.haml
Normal 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)
|
||||
@@ -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
|
||||
|
||||
3
app/views/home/_plantings.html.haml
Normal file
3
app/views/home/_plantings.html.haml
Normal 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)
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user