mirror of
https://github.com/Growstuff/growstuff.git
synced 2026-05-25 09:19:15 -04:00
Compare commits
160 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
c08beb5291 | ||
|
|
269f3164b7 | ||
|
|
9d47b2b029 | ||
|
|
81e26aaf02 | ||
|
|
d62322b498 | ||
|
|
ebb2f90294 | ||
|
|
72922a160d | ||
|
|
0699716c19 | ||
|
|
4c35987cb7 | ||
|
|
54e0806f38 | ||
|
|
99828c7c01 | ||
|
|
25d2773464 | ||
|
|
233a30a045 | ||
|
|
01a7463ae8 | ||
|
|
8a446ecbfc | ||
|
|
efc60e6313 | ||
|
|
406b2dbf04 | ||
|
|
ac056b4eb5 | ||
|
|
2394f4d237 | ||
|
|
2a4fd57050 | ||
|
|
5c885d675e | ||
|
|
0b08691160 | ||
|
|
b1052a2dbf | ||
|
|
95a923ff5f | ||
|
|
c8e34b640e | ||
|
|
6f2b4b13cd | ||
|
|
970da53873 | ||
|
|
3aa2f0bd3b | ||
|
|
8c1514bc04 | ||
|
|
d2e39f58d5 | ||
|
|
3d3a3b669e | ||
|
|
8697e56323 | ||
|
|
472b2eb192 | ||
|
|
1698157d8d | ||
|
|
ff652ae234 | ||
|
|
25e9ef892d | ||
|
|
82149d4565 | ||
|
|
fcd3e36e36 | ||
|
|
f8e51f4b45 | ||
|
|
1c8b75b7cb | ||
|
|
700fba58e8 | ||
|
|
4f64698403 | ||
|
|
14551b6ec8 | ||
|
|
0f317f624e | ||
|
|
41e26a2c74 | ||
|
|
c4c659f159 | ||
|
|
14b16b0d8c | ||
|
|
697779e67c | ||
|
|
35ce8b84db | ||
|
|
ccbdfe51f6 | ||
|
|
ff57176d60 | ||
|
|
12700d6268 | ||
|
|
17fd6f61a5 |
@@ -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
|
||||
|
||||
|
||||
7
Gemfile
7
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
|
||||
|
||||
122
Gemfile.lock
122
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.2)
|
||||
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)
|
||||
@@ -174,18 +165,18 @@ GEM
|
||||
faraday
|
||||
multi_json
|
||||
erubis (2.7.0)
|
||||
excon (0.59.0)
|
||||
excon (0.60.0)
|
||||
execjs (2.7.0)
|
||||
factory_bot (4.8.2)
|
||||
activesupport (>= 3.0.0)
|
||||
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,13 +288,13 @@ GEM
|
||||
activerecord
|
||||
kaminari-core (= 1.1.1)
|
||||
kaminari-core (1.1.1)
|
||||
kgio (2.11.0)
|
||||
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)
|
||||
@@ -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)
|
||||
@@ -353,20 +344,20 @@ GEM
|
||||
omniauth-oauth (1.1.0)
|
||||
oauth
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (1.4.0)
|
||||
oauth2 (~> 1.0)
|
||||
omniauth-oauth2 (1.5.0)
|
||||
oauth2 (~> 1.1)
|
||||
omniauth (~> 1.2)
|
||||
omniauth-twitter (1.4.0)
|
||||
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)
|
||||
mime-types
|
||||
mimemagic (~> 0.3.0)
|
||||
parallel (1.12.0)
|
||||
parallel (1.12.1)
|
||||
parser (2.4.0.2)
|
||||
ast (~> 2.3)
|
||||
pg (0.21.0)
|
||||
@@ -376,7 +367,7 @@ GEM
|
||||
moneta (~> 0.8.1)
|
||||
plupload-rails (1.2.1)
|
||||
rails (>= 3.1)
|
||||
poltergeist (1.16.0)
|
||||
poltergeist (1.17.0)
|
||||
capybara (~> 2.1)
|
||||
cliver (~> 0.3.1)
|
||||
websocket-driver (>= 0.2.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.3)
|
||||
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
|
||||
@@ -612,7 +601,7 @@ DEPENDENCIES
|
||||
omniauth-facebook
|
||||
omniauth-flickr (>= 0.0.15)
|
||||
omniauth-twitter
|
||||
pg
|
||||
pg (< 1.0.0)
|
||||
platform-api
|
||||
poltergeist
|
||||
pry
|
||||
@@ -638,9 +627,8 @@ 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
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
@@ -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');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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%
|
||||
|
||||
|
||||
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,38 +0,0 @@
|
||||
module Growstuff
|
||||
module Constants
|
||||
class PhotoModels
|
||||
PLANTING = { type: 'planting', class: 'Planting', relation: 'plantings' }.freeze
|
||||
HARVEST = { type: 'harvest', class: 'Harvest', relation: 'harvests' }.freeze
|
||||
GARDEN = { type: 'garden', class: 'Garden', relation: 'gardens' }.freeze
|
||||
SEED = { type: 'seed', class: 'Seed', relation: 'seeds' }.freeze
|
||||
|
||||
ALL = [PLANTING, HARVEST, GARDEN, SEED].freeze
|
||||
|
||||
def self.types
|
||||
ALL.map do |model|
|
||||
model[:type]
|
||||
end
|
||||
end
|
||||
|
||||
def self.relations
|
||||
ALL.map do |model|
|
||||
model[:relation]
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_relation(object, type)
|
||||
relation = ALL.select do |model|
|
||||
model[:type] == type
|
||||
end[0][:relation]
|
||||
object.send(relation)
|
||||
end
|
||||
|
||||
def self.get_item(type)
|
||||
class_name = ALL.select do |model|
|
||||
model[:type] == type
|
||||
end[0][:class]
|
||||
class_name.constantize
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -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
|
||||
14
app/controllers/admin/members_controller.rb
Normal file
14
app/controllers/admin/members_controller.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
module Admin
|
||||
class MembersController < ApplicationController
|
||||
before_action :auth!
|
||||
def index
|
||||
@members = Member.order(:login_name).paginate(page: params[:page])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def auth!
|
||||
authorize! :manage, :all
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,21 +0,0 @@
|
||||
class Admin::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
|
||||
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
|
||||
|
||||
@@ -18,6 +18,7 @@ class HarvestsController < ApplicationController
|
||||
|
||||
def show
|
||||
@matching_plantings = matching_plantings if @harvest.owner == current_member
|
||||
@photos = @harvest.photos.order(created_at: :desc).paginate(page: params[:page])
|
||||
respond_with(@harvest)
|
||||
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
|
||||
@@ -3,11 +3,19 @@ class PhotoAssociationsController < ApplicationController
|
||||
respond_to :json, :html
|
||||
|
||||
def destroy
|
||||
raise "Photos not supported" unless Photo::PHOTO_CAPABLE.include? item_class
|
||||
@photo = Photo.find_by!(id: params[:photo_id], owner: current_member)
|
||||
collection = Growstuff::Constants::PhotoModels.get_relation(@photo, params[:type])
|
||||
item_class = Growstuff::Constants::PhotoModels.get_item(params[:type])
|
||||
@item = item_class.find_by!(id: params[:id], owner_id: current_member.id)
|
||||
collection.delete(@item)
|
||||
@item = Photographing.item(item_id, item_class)
|
||||
@item.photos.delete(@photo)
|
||||
# @photo.destroy_if_unused
|
||||
respond_with(@photo)
|
||||
end
|
||||
|
||||
def item_class
|
||||
params[:type].capitalize
|
||||
end
|
||||
|
||||
def item_id
|
||||
params[:id]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,7 +36,7 @@ class PhotosController < ApplicationController
|
||||
@photo = find_or_create_photo_from_flickr_photo
|
||||
@item = item_to_link_to
|
||||
raise "Could not find this #{type} owned by you" unless @item
|
||||
collection << @item unless collection.include?(@item)
|
||||
@item.photos << @photo unless @item.photos.include? @photo
|
||||
@photo.save! if @photo.present?
|
||||
end
|
||||
respond_with @photo
|
||||
@@ -74,21 +74,12 @@ class PhotosController < ApplicationController
|
||||
end
|
||||
|
||||
# Item with photos attached
|
||||
#
|
||||
def item_to_link_to
|
||||
raise "No item id provided" if item_id.nil?
|
||||
raise "No item type provided" if item_type.nil?
|
||||
raise "Missing or invalid type provided" unless photos_supported_on_type?(item_type)
|
||||
item_class = Growstuff::Constants::PhotoModels.get_item(item_type)
|
||||
item_class.find_by!(id: params[:id], owner_id: current_member.id)
|
||||
end
|
||||
|
||||
def collection
|
||||
Growstuff::Constants::PhotoModels.get_relation(@photo, item_type)
|
||||
end
|
||||
|
||||
def photos_supported_on_type?(_type)
|
||||
Growstuff::Constants::PhotoModels.types.include?(item_type)
|
||||
item_class = item_type.capitalize
|
||||
raise "Photos not supported" unless Photo::PHOTO_CAPABLE.include? item_class
|
||||
item_class.constantize.find_by!(id: params[:id], owner_id: current_member.id)
|
||||
end
|
||||
|
||||
#
|
||||
@@ -97,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,6 +31,7 @@ class PlantingsController < ApplicationController
|
||||
@planting = Planting.includes(:owner, :crop, :garden, :photos)
|
||||
.friendly
|
||||
.find(params[:id])
|
||||
@photos = @planting.photos.order(date_taken: :desc).includes(:owner).paginate(page: params[:page])
|
||||
respond_with @planting
|
||||
end
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -19,6 +19,7 @@ class SeedsController < ApplicationController
|
||||
# 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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
class Ability
|
||||
include CanCan::Ability
|
||||
|
||||
def initialize(member) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
||||
def initialize(member)
|
||||
anon_abilities(member)
|
||||
member_abilities(member) if member.present?
|
||||
admin_abilities(member) if member.present? && member.role?(:admin)
|
||||
end
|
||||
|
||||
def anon_abilities(_member)
|
||||
# See the wiki for details: https://github.com/ryanb/cancan/wiki/Defining-Abilities
|
||||
|
||||
# everyone can do these things, even non-logged in
|
||||
@@ -9,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
|
||||
@@ -35,7 +42,9 @@ class Ability
|
||||
can :read, AlternateName do |an|
|
||||
an.crop.approved?
|
||||
end
|
||||
end
|
||||
|
||||
def member_abilities(member) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
||||
return unless member
|
||||
|
||||
# members can see even rejected or pending crops if they requested it
|
||||
@@ -106,38 +115,20 @@ class Ability
|
||||
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 }
|
||||
|
||||
# following/unfollowing permissions
|
||||
can :create, Follow
|
||||
cannot :create, Follow, followed_id: member.id # can't follow yourself
|
||||
|
||||
can :destroy, Follow
|
||||
cannot :destroy, Follow, followed_id: member.id # can't unfollow yourself
|
||||
end
|
||||
|
||||
def admin_abilities(member)
|
||||
return unless member.role? :admin
|
||||
|
||||
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
|
||||
@@ -1,18 +1,10 @@
|
||||
require_relative '../../constants/photo_models.rb'
|
||||
module PhotoCapable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
has_and_belongs_to_many :photos # rubocop:disable Rails/HasAndBelongsToMany
|
||||
has_many :photos, through: :photographings, as: :photographable
|
||||
has_many :photographings, as: :photographable, dependent: :destroy
|
||||
|
||||
before_destroy :remove_from_list
|
||||
scope :has_photos, -> { includes(:photos).where.not(photos: { id: nil }) }
|
||||
end
|
||||
|
||||
def remove_from_list
|
||||
photolist = photos.to_a # save a temp copy of the photo list
|
||||
photos.clear # clear relationship b/w object and photo
|
||||
|
||||
photolist.each(&:destroy_if_unused)
|
||||
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
|
||||
|
||||
@@ -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
|
||||
@@ -1,31 +1,19 @@
|
||||
require_relative '../constants/photo_models.rb'
|
||||
class Photo < ActiveRecord::Base
|
||||
belongs_to :owner, class_name: 'Member'
|
||||
|
||||
Growstuff::Constants::PhotoModels.relations.each do |relation|
|
||||
has_and_belongs_to_many relation.to_sym # rubocop:disable Rails/HasAndBelongsToMany
|
||||
end
|
||||
PHOTO_CAPABLE = %w(Garden Planting Harvest Seed).freeze
|
||||
|
||||
before_destroy { all_associations.clear }
|
||||
has_many :photographings, foreign_key: :photo_id, dependent: :destroy
|
||||
# creates a relationship for each assignee type
|
||||
PHOTO_CAPABLE.each do |type|
|
||||
has_many type.downcase.pluralize.to_s.to_sym,
|
||||
through: :photographings,
|
||||
source: :photographable,
|
||||
source_type: type
|
||||
end
|
||||
|
||||
default_scope { joins(:owner) } # Ensures the owner still exists
|
||||
|
||||
def associations?
|
||||
plantings.any? || harvests.any? || gardens.any? || seeds.any?
|
||||
end
|
||||
|
||||
def all_associations
|
||||
associations = []
|
||||
Growstuff::Constants::PhotoModels.relations.each do |association_name|
|
||||
associations << send(association_name.to_s).to_a
|
||||
end
|
||||
associations.flatten!
|
||||
end
|
||||
|
||||
def destroy_if_unused
|
||||
destroy if all_associations.empty?
|
||||
end
|
||||
|
||||
# This is split into a side-effect free method and a side-effecting method
|
||||
# for easier stubbing and testing.
|
||||
def flickr_metadata
|
||||
@@ -39,10 +27,19 @@ 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
|
||||
|
||||
def associations?
|
||||
photographings.size.positive?
|
||||
end
|
||||
|
||||
def destroy_if_unused
|
||||
destroy unless associations?
|
||||
end
|
||||
|
||||
def calculate_title(info)
|
||||
if id && title # already has a title saved
|
||||
title
|
||||
@@ -53,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
|
||||
|
||||
12
app/models/photographing.rb
Normal file
12
app/models/photographing.rb
Normal file
@@ -0,0 +1,12 @@
|
||||
class Photographing < ActiveRecord::Base
|
||||
belongs_to :photo
|
||||
belongs_to :photographable, polymorphic: true
|
||||
|
||||
def self.item(item_id, item_type)
|
||||
find_by!(photographable_id: item_id, photographable_type: item_type).photographable
|
||||
end
|
||||
|
||||
def item
|
||||
find_by!(photographable_id: photographable_id, photographable_type: photographable_type).photographable
|
||||
end
|
||||
end
|
||||
@@ -4,12 +4,12 @@ class Planting < ActiveRecord::Base
|
||||
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
|
||||
@@ -26,6 +26,7 @@ class Planting < ActiveRecord::Base
|
||||
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 {
|
||||
joins("JOIN members m ON (m.id=plantings.owner_id)
|
||||
LEFT OUTER JOIN plantings p2
|
||||
|
||||
@@ -43,7 +43,7 @@ class Post < ActiveRecord::Base
|
||||
|
||||
# return posts sorted by recent activity
|
||||
def self.recently_active
|
||||
Post.all.sort do |a, b|
|
||||
Post.order(created_at: :desc).sort do |a, b|
|
||||
b.recent_activity <=> a.recent_activity
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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
|
||||
@@ -16,8 +16,6 @@ class Seed < ActiveRecord::Base
|
||||
#
|
||||
# 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 +36,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 +47,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
|
||||
@@ -2,16 +2,21 @@
|
||||
|
||||
%h2 Manage
|
||||
|
||||
%ul#admin_links
|
||||
%li= link_to "Account types", account_types_path
|
||||
%li= link_to "Alternate names", alternate_names_path
|
||||
%li= link_to "Scientific names", scientific_names_path
|
||||
%li= link_to "Products", products_path
|
||||
%li= link_to "Roles", roles_path
|
||||
%li= link_to "Forums", forums_path
|
||||
%li= link_to "Newsletter subscribers", admin_newsletter_path
|
||||
%li= link_to "CMS", comfy_admin_cms_path
|
||||
.row
|
||||
.col-md-4
|
||||
%h2 Site admin
|
||||
%ul#site_admin
|
||||
%li= link_to "Roles", roles_path
|
||||
%li= link_to "Forums", forums_path
|
||||
%li= link_to "CMS", comfy_admin_cms_path
|
||||
|
||||
%h2 Orders
|
||||
|
||||
= render "admin/orders/searchform"
|
||||
.col-md-4
|
||||
%h2 Crop data admin
|
||||
%ul
|
||||
%li= link_to "Alternate names", alternate_names_path
|
||||
%li= link_to "Scientific names", scientific_names_path
|
||||
.col-md-4
|
||||
%h2 Member admin
|
||||
%ul
|
||||
%li= link_to "Newsletter subscribers", admin_newsletter_path
|
||||
%li= link_to "Members", admin_members_path
|
||||
|
||||
15
app/views/admin/members/index.html.haml
Normal file
15
app/views/admin/members/index.html.haml
Normal file
@@ -0,0 +1,15 @@
|
||||
.pagination
|
||||
= page_entries_info @members
|
||||
= will_paginate @members
|
||||
|
||||
|
||||
%table.table.table-striped
|
||||
%tr
|
||||
%th Name
|
||||
%th Email
|
||||
%th
|
||||
%th
|
||||
- @members.each do |member|
|
||||
%tr
|
||||
%td= ember.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'
|
||||
@@ -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,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
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
= 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?
|
||||
@@ -23,37 +26,51 @@
|
||||
|
||||
.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}
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
= 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
|
||||
@@ -32,7 +37,11 @@
|
||||
Why not
|
||||
= link_to 'tell us more.', edit_garden_path(@garden)
|
||||
|
||||
%h3 What's planted here?
|
||||
%h3 Garden timeline
|
||||
.row
|
||||
= timeline garden_timeline_path(@garden), adapter: "google"
|
||||
|
||||
%h3 Current plantings in garden
|
||||
.row
|
||||
- if @current_plantings.size.positive?
|
||||
- @current_plantings.each do |planting|
|
||||
|
||||
@@ -48,15 +48,4 @@
|
||||
:growstuff_markdown
|
||||
#{ @harvest.description != "" ? strip_tags(@harvest.description) : "No description given." }
|
||||
|
||||
- if !@harvest.photos.empty? || (can?(:edit, @harvest) && can?(:create, Photo))
|
||||
%h2 Pictures
|
||||
|
||||
%ul.thumbnails
|
||||
- @harvest.photos.each do |p|
|
||||
.col-md-2.six-across
|
||||
= render partial: 'photos/thumbnail', locals: { photo: p }
|
||||
- if can?(:create, Photo) && can?(:edit, @harvest)
|
||||
.col-md-2
|
||||
.thumbnail{ style: 'height: 220px' }
|
||||
%p{ style: 'text-align: center; padding-top: 50px' }
|
||||
= link_to "Add photo", new_photo_path(type: "harvest", id: @harvest.id), class: 'btn btn-primary'
|
||||
= render 'photos/item_photos', item: @harvest, type: 'harvest', photos: @photos
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
.col-md-4.hidden-xs
|
||||
- cache cache_key_for(Planting) do
|
||||
%h2= t('.recently_planted')
|
||||
= render partial: 'plantings/list', locals: { plantings: Planting.includes(:owner, :photos).interesting.first(6) }
|
||||
= render 'plantings/list', plantings: Planting.includes(:owner, :photos).interesting.recent.first(6)
|
||||
|
||||
.row
|
||||
.col-md-12
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
- posts = Post.limit(6)
|
||||
- if posts
|
||||
= render partial: "posts/summary", locals: { posts: posts, howmany: 6 }
|
||||
= render "posts/summary", posts: posts, howmany: 6
|
||||
|
||||
- cache cache_key_for(Forum) do
|
||||
- forums = Forum.all.order(:name)
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
!!! 5
|
||||
%html{ lang: "en", prefix: "og: http://ogp.me/ns#" }
|
||||
= yield :scripts
|
||||
= render partial: "layouts/meta"
|
||||
%body
|
||||
= render partial: "layouts/header"
|
||||
@@ -27,5 +28,4 @@
|
||||
\==================================================
|
||||
/ Placed at the end of the document so the pages load faster
|
||||
= javascript_include_tag "application"
|
||||
|
||||
!= Growstuff::Application.config.analytics_code
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
%h3 Account details
|
||||
|
||||
%p
|
||||
%strong Member since:
|
||||
= member.created_at.to_s(:date)
|
||||
|
||||
%p
|
||||
%strong Account type:
|
||||
= member.account_type
|
||||
account
|
||||
|
||||
%p
|
||||
%strong Last Login:
|
||||
= member.last_sign_in_at
|
||||
|
||||
%p
|
||||
%strong Member Roles:
|
||||
%br
|
||||
- if member.role? :admin
|
||||
Administrator
|
||||
- if member.role? :crop_wrangler
|
||||
Crop Wrangler
|
||||
- else
|
||||
Member
|
||||
9
app/views/members/_roles.html.haml
Normal file
9
app/views/members/_roles.html.haml
Normal file
@@ -0,0 +1,9 @@
|
||||
%p
|
||||
%strong Member Roles:
|
||||
%br
|
||||
- if member.role? :admin
|
||||
Administrator
|
||||
- if member.role? :crop_wrangler
|
||||
Crop Wrangler
|
||||
- unless (member.role?(:admin) || member.role?(:crop_wrangler))
|
||||
Member
|
||||
@@ -1,3 +1,10 @@
|
||||
%p
|
||||
%strong Member since:
|
||||
= member.created_at.to_s(:date)
|
||||
%p
|
||||
%strong Last Login:
|
||||
= member.last_sign_in_at
|
||||
|
||||
%h3 Activity
|
||||
|
||||
%ul.list-inline
|
||||
@@ -33,4 +40,3 @@
|
||||
= link_to pluralize(member.followers.size, "follower"), member_followers_path(member)
|
||||
- else
|
||||
0 followers
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
- content_for :buttonbar do
|
||||
- if can? :update, @member
|
||||
= link_to 'Edit profile', edit_member_registration_path, class: 'btn btn-default'
|
||||
- if @member == current_member && !@member.paid?
|
||||
= link_to "Upgrade account", shop_path, class: 'btn btn-default'
|
||||
- if can?(:create, Notification) && current_member != @member
|
||||
= link_to 'Send message', new_notification_path(recipient_id: @member.id), class: 'btn btn-default'
|
||||
|
||||
@@ -33,7 +31,7 @@
|
||||
= render partial: "gardens", locals: { member: @member, gardens: @gardens }
|
||||
.col-md-3
|
||||
= render partial: "avatar", locals: { member: @member }
|
||||
= render partial: "account", locals: { member: @member }
|
||||
= render partial: "roles", locals: { member: @member }
|
||||
= render partial: "stats", locals: { member: @member }
|
||||
= render partial: "contact", locals: { member: @member,
|
||||
twitter_auth: @twitter_auth,
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
- content_for :title, "Completed order"
|
||||
|
||||
%p Thank you for your order.
|
||||
|
||||
%p
|
||||
%strong Completed at:
|
||||
= @order.completed_at
|
||||
|
||||
%p
|
||||
%strong Order number:
|
||||
= @order.id
|
||||
|
||||
= render "shared/account_status"
|
||||
|
||||
%h2 Order items
|
||||
|
||||
%table.table.table-striped
|
||||
%tr
|
||||
%th Product
|
||||
%th Price
|
||||
%th Quantity
|
||||
%th Subtotal
|
||||
- total = 0
|
||||
- @order.order_items.each do |i|
|
||||
%tr
|
||||
%td= i.product.name
|
||||
%td
|
||||
= price_with_currency(i.price)
|
||||
%td= i.quantity
|
||||
%td
|
||||
- subtotal = i.price * i.quantity
|
||||
- total += subtotal
|
||||
= price_with_currency(subtotal)
|
||||
|
||||
%tr
|
||||
%td
|
||||
%td
|
||||
%td
|
||||
%strong Total:
|
||||
%td
|
||||
%strong
|
||||
= price_with_currency(total)
|
||||
|
||||
%p
|
||||
= link_to "View other orders/order history", orders_path
|
||||
@@ -1,44 +0,0 @@
|
||||
- content_for :title, "Your Account"
|
||||
|
||||
= render "shared/account_status"
|
||||
|
||||
|
||||
%h2 Orders
|
||||
|
||||
|
||||
- if current_member.orders.present?
|
||||
|
||||
%p
|
||||
Your order history shows what you have bought via our
|
||||
= succeed "." do
|
||||
= link_to "shop", shop_path
|
||||
|
||||
%table.table.table-striped
|
||||
%tr
|
||||
%th Order number
|
||||
%th Date completed
|
||||
%th Items
|
||||
%th
|
||||
- @orders.each do |order|
|
||||
%tr
|
||||
%td= order.id
|
||||
%td
|
||||
- if order.completed_at
|
||||
= order.completed_at.to_s
|
||||
- else
|
||||
In progress
|
||||
%td
|
||||
- unless order.order_items.empty?
|
||||
- order.order_items.each do |o|
|
||||
= o.quantity
|
||||
x
|
||||
= o.product.name
|
||||
@
|
||||
= price_with_currency(o.price)
|
||||
%br/
|
||||
%td= link_to 'Details', order, class: 'btn btn-default btn-xs'
|
||||
- else
|
||||
%p
|
||||
You have not made any orders. You can place an order via our
|
||||
= succeed "." do
|
||||
= link_to "shop", shop_path
|
||||
@@ -1,84 +0,0 @@
|
||||
- content_for :title, @order.completed_at ? "Order details (##{@order.id})" : "Current order"
|
||||
|
||||
%p
|
||||
%strong Order number:
|
||||
= @order.id
|
||||
|
||||
%p
|
||||
%strong Ordered by:
|
||||
= link_to @order.member, @order.member
|
||||
|
||||
%p
|
||||
%strong Date begun:
|
||||
= @order.created_at.to_s
|
||||
|
||||
- if @order.completed_at
|
||||
%p
|
||||
%strong Date completed:
|
||||
= @order.completed_at.to_s
|
||||
|
||||
- if @order.referral_code
|
||||
%p
|
||||
%strong Referral code:
|
||||
= @order.referral_code
|
||||
|
||||
- if current_member.role? :admin
|
||||
%p
|
||||
%strong Paypal Express token:
|
||||
= @order.paypal_express_token
|
||||
%p
|
||||
%strong Paypal Express payer ID:
|
||||
= @order.paypal_express_payer_id
|
||||
|
||||
%h2 Order items
|
||||
|
||||
%table.table.table-striped
|
||||
%tr
|
||||
%th Product
|
||||
%th Price
|
||||
%th Quantity
|
||||
%th Subtotal
|
||||
- @order.order_items.each do |i|
|
||||
%tr
|
||||
%td= i.product.name
|
||||
%td
|
||||
= price_with_currency(i.price)
|
||||
%td= i.quantity
|
||||
%td
|
||||
- subtotal = i.price * i.quantity
|
||||
= price_with_currency(subtotal)
|
||||
|
||||
%tr
|
||||
%td
|
||||
%td
|
||||
%td
|
||||
%strong Total:
|
||||
%td
|
||||
%strong
|
||||
= price_with_currency(@order.total)
|
||||
= forex_link(@order.total)
|
||||
|
||||
- if @order.errors.any?
|
||||
.alert
|
||||
#error_explanation
|
||||
%h3
|
||||
= pluralize(@order.errors.size, "error")
|
||||
stopped you from checking out:
|
||||
%ul
|
||||
- @order.errors.full_messages.each do |msg|
|
||||
%li= msg
|
||||
|
||||
- if can?(:complete, @order) || can?(:destroy, @order)
|
||||
= form_tag(checkout_order_path(@order), method: :get, class: 'form-inline') do
|
||||
%p
|
||||
- if can? :complete, @order
|
||||
= label_tag :referral_code, "Do you have a referral code?"
|
||||
= text_field_tag :referral_code, @order.referral_code, class: 'input-medium'
|
||||
= submit_tag "Checkout with PayPal", class: 'btn btn-primary'
|
||||
- if can? :destroy, @order
|
||||
= link_to 'Delete this order', @order, method: :delete,
|
||||
data: { confirm: 'Are you sure?' },
|
||||
class: 'btn btn-default'
|
||||
= link_to "View other orders/order history", orders_path, class: 'btn btn-default'
|
||||
|
||||
%p
|
||||
16
app/views/photos/_item_photos.haml
Normal file
16
app/views/photos/_item_photos.haml
Normal file
@@ -0,0 +1,16 @@
|
||||
- if photos.size.positive? || (can?(:edit, item) && can?(:create, Photo))
|
||||
%h2 Photos
|
||||
- if photos.size.positive?
|
||||
.row
|
||||
.pagination
|
||||
= page_entries_info photos
|
||||
= will_paginate photos
|
||||
.row
|
||||
- photos.each do |photo|
|
||||
.col-md-2.six-across= render 'photos/thumbnail', photo: photo
|
||||
- if can?(:create, Photo) && can?(:edit, item)
|
||||
.col-md-2
|
||||
.thumbnail
|
||||
= link_to new_photo_path(type: type, id: item.id), class: 'btn btn-primary' do
|
||||
%span.glyphicon.glyphicon-camera{ title: "Add photo" }
|
||||
Add photo
|
||||
@@ -21,7 +21,7 @@
|
||||
= f.label :garden_id, 'Where did you plant it?', class: 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= collection_select(:planting, :garden_id,
|
||||
Garden.active.where(owner_id: current_member),
|
||||
current_member.gardens.active.order("lower(gardens.name)"),
|
||||
:id, :name,
|
||||
selected: @planting.garden_id || @garden.id,
|
||||
class: 'form-control')
|
||||
|
||||
@@ -83,15 +83,4 @@
|
||||
:growstuff_markdown
|
||||
#{ @planting.description != "" ? strip_tags(@planting.description) : "No description given." }
|
||||
|
||||
- if !@planting.photos.empty? || (can?(:edit, @planting) && can?(:create, Photo))
|
||||
%h2 Photos
|
||||
|
||||
.row
|
||||
- @planting.photos.includes(:owner).each do |p|
|
||||
.col-md-2.six-across
|
||||
= render partial: 'photos/thumbnail', locals: { photo: p }
|
||||
- if can?(:create, Photo) && can?(:edit, @planting)
|
||||
.col-md-2
|
||||
.thumbnail{ style: 'height: 220px' }
|
||||
%p{ style: 'text-align: center; padding-top: 50px' }
|
||||
= link_to "Add photo", new_photo_path(type: "planting", id: @planting.id), class: 'btn btn-primary'
|
||||
= render 'photos/item_photos', item: @planting, type: 'planting', photos: @photos
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
= form_for @product do |f|
|
||||
- if @product.errors.any?
|
||||
#error_explanation
|
||||
%h2
|
||||
= pluralize(@product.errors.size, "error")
|
||||
prohibited this product from being saved:
|
||||
%ul
|
||||
- @product.errors.full_messages.each do |msg|
|
||||
%li= msg
|
||||
|
||||
.field
|
||||
= f.label :name
|
||||
= f.text_field :name, class: 'form-control'
|
||||
.field
|
||||
= f.label :description
|
||||
= f.text_area :description, class: 'form-control'
|
||||
.field
|
||||
= f.label :min_price, "Minimum price (in cents)"
|
||||
= f.text_field :min_price
|
||||
.field
|
||||
= f.label :recommended_price, "Recommended price (in cents)"
|
||||
= f.text_field :recommended_price
|
||||
.field
|
||||
= f.label :account_type
|
||||
= collection_select(:product, :account_type_id, AccountType.all, :id,
|
||||
:name, selected: @product.account_type_id)
|
||||
.field
|
||||
= f.label :paid_months
|
||||
= f.text_field :paid_months
|
||||
.form-group
|
||||
.actions
|
||||
= f.submit 'Save'
|
||||
@@ -1,7 +0,0 @@
|
||||
- content_for :title, "Editing product"
|
||||
|
||||
= render 'form'
|
||||
|
||||
= link_to 'Show', @product
|
||||
\|
|
||||
= link_to 'Back', products_path
|
||||
@@ -1,29 +0,0 @@
|
||||
- content_for :title, "Listing products"
|
||||
|
||||
%table
|
||||
%tr
|
||||
%th Name
|
||||
%th Description
|
||||
%th Min price
|
||||
%th Recommended price
|
||||
%th Account type
|
||||
%th Paid months
|
||||
%th
|
||||
%th
|
||||
%th
|
||||
|
||||
- @products.each do |product|
|
||||
%tr
|
||||
%td= product.name
|
||||
%td= product.description
|
||||
%td= product.min_price
|
||||
%td= product.recommended_price
|
||||
%td= product.account_type ? product.account_type.name : ""
|
||||
%td= product.paid_months
|
||||
%td= link_to 'Show', product
|
||||
%td= link_to 'Edit', edit_product_path(product)
|
||||
%td= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' }
|
||||
|
||||
%br
|
||||
|
||||
= link_to 'New Product', new_product_path
|
||||
@@ -1,5 +0,0 @@
|
||||
- content_for :title, "New product"
|
||||
|
||||
= render 'form'
|
||||
|
||||
= link_to 'Back', products_path
|
||||
@@ -1,25 +0,0 @@
|
||||
%p#notice= notice
|
||||
|
||||
%p
|
||||
%b Name:
|
||||
= @product.name
|
||||
%p
|
||||
%b Description:
|
||||
:growstuff_markdown
|
||||
#{strip_tags(@product.description)}
|
||||
%p
|
||||
%b Min price:
|
||||
= @product.min_price
|
||||
%p
|
||||
%b Recommended price:
|
||||
= @product.recommended_price
|
||||
%p
|
||||
%b Account type:
|
||||
= @product.account_type.name
|
||||
%p
|
||||
%b Paid months:
|
||||
= @product.paid_months
|
||||
|
||||
= link_to 'Edit', edit_product_path(@product)
|
||||
\|
|
||||
= link_to 'Back', products_path
|
||||
@@ -1,18 +1,19 @@
|
||||
= form_for @role do |f|
|
||||
- if @role.errors.any?
|
||||
#error_explanation
|
||||
%h2
|
||||
= pluralize(@role.errors.size, "error")
|
||||
prohibited this role from being saved:
|
||||
%ul
|
||||
- @role.errors.full_messages.each do |msg|
|
||||
%li= msg
|
||||
.row
|
||||
- if @role.errors.any?
|
||||
#error_explanation
|
||||
%h2
|
||||
= pluralize(@role.errors.size, "error")
|
||||
prohibited this role from being saved:
|
||||
%ul
|
||||
- @role.errors.full_messages.each do |msg|
|
||||
%li= msg
|
||||
|
||||
.field
|
||||
= f.label :name
|
||||
= f.text_field :name
|
||||
.col-md2= f.label :name
|
||||
.col-md10= f.text_field :name
|
||||
.field
|
||||
= f.label :description
|
||||
= f.text_area :description
|
||||
.col-md2= f.label :description
|
||||
.col-md10= f.text_area :description
|
||||
.actions
|
||||
= f.submit 'Save'
|
||||
= f.submit 'Save', class: 'btn btn-default'
|
||||
|
||||
@@ -2,6 +2,4 @@
|
||||
|
||||
= render 'form'
|
||||
|
||||
= link_to 'Show', @role
|
||||
\|
|
||||
= link_to 'Back', roles_path
|
||||
|
||||
@@ -3,17 +3,16 @@
|
||||
- if can? :create, Role
|
||||
%p= link_to 'New Role', new_role_path, class: 'btn btn-primary'
|
||||
|
||||
%table
|
||||
%table.table.table-striped
|
||||
%tr
|
||||
%th Name
|
||||
%th Description
|
||||
%th
|
||||
%th
|
||||
%th
|
||||
|
||||
- @roles.each do |role|
|
||||
%tr
|
||||
%td= link_to role.name, role
|
||||
%td= role.name
|
||||
%td= role.description
|
||||
- if can? :edit, role
|
||||
%td= link_to 'Edit', edit_role_path(role), class: 'btn btn-default btn-xs'
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user