mirror of
https://github.com/Growstuff/growstuff.git
synced 2026-05-07 23:36:15 -04:00
merge in changes from dev branch
This commit is contained in:
41
.travis.yml
41
.travis.yml
@@ -1,12 +1,37 @@
|
||||
---
|
||||
sudo: false
|
||||
language: ruby
|
||||
|
||||
env: GROWSTUFF_SITE_NAME="Growstuff (travis)" RAILS_SECRET_TOKEN='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
||||
bundler_args: --without development production staging
|
||||
cache: bundler
|
||||
env:
|
||||
matrix:
|
||||
- GROWSTUFF_SITE_NAME="Growstuff (travis)" RAILS_SECRET_TOKEN='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
||||
global:
|
||||
secure: "Z5TpM2jEX4UCvNePnk/LwltQX48U2u9BRc+Iypr1x9QW2o228QJhPIOH39a8RMUrepGnkQIq9q3ZRUn98RfrJz1yThtlNFL3NmzdQ57gKgjGwfpa0e4Dwj/ZJqV2D84tDGjvdVYLP7zzaYZxQcwk/cgNpzKf/jq97HLNP7CYuf4="
|
||||
bundler_args: "--without development production staging"
|
||||
rvm:
|
||||
- 2.1.5
|
||||
- 2.1.5
|
||||
before_script:
|
||||
- psql -c 'create database growstuff_test;' -U postgres
|
||||
- psql -c 'create database growstuff_test;' -U postgres
|
||||
script:
|
||||
- bundle exec rake db:migrate --trace
|
||||
- bundle exec rspec spec/
|
||||
- bundle exec rake db:migrate --trace
|
||||
- bundle exec rspec spec/
|
||||
services:
|
||||
- elasticsearch
|
||||
before_deploy:
|
||||
- bundle exec script/heroku_maintenance.rb on
|
||||
deploy:
|
||||
provider: heroku
|
||||
api_key:
|
||||
secure: WrQxf0fEKkCdXrjcejurobOnNNz3he4dDwjBbToXbQTQNDObPp7NetJrLsfM8FiUFEeOuvhIHHiDQtMvY720zGGAGxDptvgFS+0QHCUqoTRZA/yFfUmHlG2jROXTzk5uVK0AE4k6Ion5kX8+mM0EnMT/7u+MTFiukrJctSiEXfg=
|
||||
on:
|
||||
repo: Growstuff/growstuff
|
||||
app:
|
||||
dev: growstuff-staging
|
||||
travis_deploy: tranquil-basin-3130
|
||||
travis_containers: tranquil-basin-3130
|
||||
run:
|
||||
- "rake db:migrate"
|
||||
- "script/deploy-tasks.sh"
|
||||
- restart
|
||||
after_deploy:
|
||||
- bundle exec script/heroku_maintenance.rb off
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
Thanks for contributing to Growstuff!
|
||||
|
||||
Please include the following information in your pull request:
|
||||
When you create a pull request, please include the following:
|
||||
|
||||
* A link to the [Pivotal Tracker](http://tracker.growstuff.org/) task to which it relates.
|
||||
* Mention the issue it solves (eg. #123)
|
||||
* Your code should follow our [Coding style guide](http://wiki.growstuff.org/index.php/Coding_style_guide)
|
||||
* Make sure you have automated tests for your work, where possible.
|
||||
* Add your name (and that of your pair partner, if any) to [CONTRIBUTORS.md](CONTRIBUTORS.md).
|
||||
|
||||
@@ -11,10 +11,11 @@ submit the change with your pull request.
|
||||
- Alex Bayley / [Skud](https://github.com/Skud)
|
||||
- Cesy / [cesy](https://github.com/cesy)
|
||||
- Miles Gould / [pozorvlak](https://github.com/pozorvlak)
|
||||
- Joseph Caudle / [jcaudle](https://github.com/jcaudle)
|
||||
- Taylor Griffin / [tygriffin](https://github.com/tygriffin)
|
||||
|
||||
## Contributors
|
||||
|
||||
- Joseph Caudle / [jcaudle](https://github.com/jcaudle)
|
||||
- Ricky Amianym / [amianym](https://github.com/amianym)
|
||||
- Juliet Kemp / [julietk](https://github.com/julietk)
|
||||
- Federico Mena Quintero / [federicomenaquintero](https://github.com/federicomenaquintero)
|
||||
@@ -40,7 +41,6 @@ submit the change with your pull request.
|
||||
- Marty Hines / [martyhines](https://github.com/martyhines)
|
||||
- Amelia Greenhall / [ameliagreenhall](https://github.com/ameliagreenhall)
|
||||
- Barb Natali / [barbnatali](https://github.com/barbnatali)
|
||||
- Taylor Griffin / [tygriffin](https://github.com/tygriffin)
|
||||
- Marlena Compton / [Marlena](https://github.com/marlena)
|
||||
- Elizabeth A. Kari / [catfriend](https://github.com/catfriend)
|
||||
- Cheri Allen / [cherimarie](https://github.com/cherimarie)
|
||||
@@ -51,5 +51,8 @@ submit the change with your pull request.
|
||||
- Yoong Kang Lim / [yoongkang](https://github.com/yoongkang)
|
||||
- Kevin Yang / [kevieyang](https://github.com/kevieyang)
|
||||
- Justin Hamman / [juzham](https://github.com/juzham)
|
||||
- Rocky Jaiswal / [rocky-jaiswal](https://github.com/rocky-jaiswal)
|
||||
- Robert Landreaux / [robertlandreaux](https://github.com/robertlandreaux)
|
||||
- Savant Krishna / [sksavant](https://github.com/sksavant)
|
||||
- Marlena Compton / [marlena] (https://github/marlena)
|
||||
- Ryan Dy / [rdy] (https://github/rdy)
|
||||
- Ryan Dy / [rdy] (https://github/rdy)
|
||||
170
Gemfile
170
Gemfile
@@ -1,92 +1,55 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
ruby "2.1.5"
|
||||
ruby '2.1.5'
|
||||
|
||||
gem 'rails', '4.1.9'
|
||||
|
||||
gem 'bundler', '>=1.1.5'
|
||||
|
||||
gem 'rails', '3.2.13'
|
||||
gem 'rack', '~>1.4.5'
|
||||
gem 'json', '~>1.7.7'
|
||||
gem 'sass-rails', '~> 4.0.4'
|
||||
gem 'coffee-rails', '~> 4.1.0'
|
||||
gem 'haml'
|
||||
|
||||
# Another CSS preprocessor, used for Bootstrap overrides
|
||||
gem 'less', '~>2.5.0'
|
||||
gem 'less-rails', '~> 2.5.0'
|
||||
# CSS framework
|
||||
gem 'less-rails-bootstrap', '~> 3.2.0'
|
||||
|
||||
gem 'uglifier', '~> 2.5.3' # JavaScript compressor
|
||||
|
||||
gem 'jquery-rails'
|
||||
gem 'jquery-ui-rails', '~> 5.0.2'
|
||||
gem 'js-routes' # provides access to Rails routes in Javascript
|
||||
gem 'flickraw'
|
||||
|
||||
gem 'leaflet-rails'
|
||||
gem 'leaflet-markercluster-rails'
|
||||
gem 'unicorn' # http server
|
||||
|
||||
gem 'unicorn' # http server
|
||||
gem 'pg'
|
||||
gem 'figaro' # for handling config via ENV variables
|
||||
gem 'cancancan', '~> 1.9' # for checking member privileges
|
||||
gem 'gibbon' # for Mailchimp newsletter subscriptions
|
||||
gem 'csv_shaper' # CSV export
|
||||
gem 'ruby-units' # for unit conversion
|
||||
|
||||
gem 'figaro' # for handling config via ENV variables
|
||||
|
||||
gem 'cancan' # for checking member privileges
|
||||
|
||||
gem 'gibbon' # for Mailchimp newsletter subscriptions
|
||||
|
||||
gem 'csv_shaper' # CSV export
|
||||
gem 'comfortable_mexican_sofa', '~> 1.12.0' # content management system
|
||||
|
||||
# vendored activemerchant for testing- needed for bogus paypal
|
||||
# gateway monkeypatch
|
||||
gem 'activemerchant', '1.33.0',
|
||||
:path => 'vendor/gems/activemerchant-1.33.0',
|
||||
:path => 'vendor/gems/activemerchant-1.33.0',
|
||||
:require => 'active_merchant'
|
||||
gem 'active_utils', '1.0.5',
|
||||
:path => 'vendor/gems/active_utils-1.0.5'
|
||||
:path => 'vendor/gems/active_utils-1.0.5'
|
||||
|
||||
group :production, :staging do
|
||||
gem 'newrelic_rpm'
|
||||
gem 'dalli'
|
||||
gem 'memcachier'
|
||||
gem 'rails_12factor' # supresses heroku plugin injection
|
||||
end
|
||||
|
||||
# Gems used only for assets and not required
|
||||
# in production environments by default.
|
||||
group :assets do
|
||||
# CSS preprocessor, used for app/assets/stylesheets/application.css
|
||||
gem 'sass-rails', '~> 3.2.3'
|
||||
# CoffeeScript is a Python-like language that compiles to JavaScript
|
||||
gem 'coffee-rails', '~> 3.2.1'
|
||||
|
||||
# less-rails depends on a JavaScript engine; we use therubyracer.
|
||||
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
|
||||
# long term, we'll probably want node.js for performance, but this will do
|
||||
# for now as it's easier for new people to install
|
||||
gem "therubyracer", "~> 0.12", :platforms => :ruby
|
||||
# libv8 is needed by therubyracer and is a bit finicky
|
||||
gem 'libv8', '3.16.14.7'
|
||||
|
||||
# Another CSS preprocessor, used for Bootstrap overrides
|
||||
gem "less", '~>2.5.0'
|
||||
gem "less-rails", '~> 2.5.0'
|
||||
# CSS framework
|
||||
gem "less-rails-bootstrap", '~> 3.2.0'
|
||||
|
||||
gem 'uglifier', '>= 1.0.3' # JavaScript compressor
|
||||
|
||||
gem 'compass-rails', '~> 1.0.3' # Yet Another CSS framework
|
||||
end
|
||||
|
||||
gem 'jquery-rails'
|
||||
gem 'jquery-ui-rails'
|
||||
gem 'js-routes' # provides access to Rails routes in Javascript
|
||||
gem 'flickraw'
|
||||
|
||||
# To use ActiveModel has_secure_password
|
||||
# gem 'bcrypt-ruby', '~> 3.0.0'
|
||||
|
||||
# To use Jbuilder templates for JSON
|
||||
# gem 'jbuilder'
|
||||
|
||||
# Use unicorn as the app server
|
||||
# gem 'unicorn'
|
||||
|
||||
group :development do
|
||||
# A debugger and irb alternative. Pry doesn't play nice
|
||||
# with unicorn, so start a Webrick server when debugging
|
||||
# with Pry
|
||||
gem 'pry'
|
||||
gem 'better_errors'
|
||||
gem 'binding_of_caller'
|
||||
gem 'letter_opener'
|
||||
end
|
||||
# less-rails depends on a JavaScript engine; we use therubyracer.
|
||||
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
|
||||
# long term, we'll probably want node.js for performance, but this will do
|
||||
# for now as it's easier for new people to install
|
||||
gem 'therubyracer', '~> 0.12', :platforms => :ruby
|
||||
# libv8 is needed by therubyracer and is a bit finicky
|
||||
gem 'libv8', '3.16.14.7'
|
||||
|
||||
# Markdown formatting for updates etc
|
||||
gem 'bluecloth'
|
||||
@@ -95,10 +58,10 @@ gem 'bluecloth'
|
||||
gem 'will_paginate', '~> 3.0'
|
||||
|
||||
# user signup/login/etc
|
||||
gem 'devise', '~> 3.2.0'
|
||||
gem 'devise', '~> 3.4.1'
|
||||
|
||||
# nicely formatted URLs
|
||||
gem 'friendly_id', '~> 4.0.10'
|
||||
gem 'friendly_id', '~> 5.0.4'
|
||||
|
||||
# gravatars
|
||||
gem 'gravatar-ultimate'
|
||||
@@ -116,20 +79,51 @@ gem 'omniauth'
|
||||
gem 'omniauth-twitter'
|
||||
gem 'omniauth-flickr', '>= 0.0.15'
|
||||
|
||||
# client for Elasticsearch. Elasticsearch is a flexible
|
||||
# and powerful, distributed, real-time search and analytics engine.
|
||||
# An example of the use in the project is fuzzy crop search.
|
||||
gem "elasticsearch-model"
|
||||
gem "elasticsearch-rails"
|
||||
|
||||
gem 'rake', '>= 10.0.0'
|
||||
|
||||
group :development, :test do
|
||||
gem 'byebug' # debugging
|
||||
gem 'haml-rails' # HTML templating language
|
||||
gem 'rspec-rails', '~> 2.12.1' # unit testing framework
|
||||
gem 'database_cleaner', '~> 1.3.0'
|
||||
gem 'webrat' # provides HTML matchers for view tests
|
||||
gem 'factory_girl_rails', '~> 4.0' # for creating test data
|
||||
gem 'coveralls', require: false # coverage analysis
|
||||
gem 'capybara' # integration tests
|
||||
gem 'capybara-email' # integration tests for email
|
||||
gem 'poltergeist', '~> 1.5.1' # for headless JS testing
|
||||
gem 'i18n-tasks' # adds tests for finding missing and unused translations
|
||||
gem 'jasmine'
|
||||
gem 'd3-rails'
|
||||
group :production, :staging do
|
||||
gem 'newrelic_rpm'
|
||||
gem 'dalli'
|
||||
gem 'memcachier'
|
||||
gem 'rails_12factor' # supresses heroku plugin injection
|
||||
gem 'bonsai-elasticsearch-rails' # Integration with Bonsa-Elasticsearch on heroku
|
||||
end
|
||||
|
||||
group :development do
|
||||
# A debugger and irb alternative. Pry doesn't play nice
|
||||
# with unicorn, so start a Webrick server when debugging
|
||||
# with Pry
|
||||
gem 'pry'
|
||||
gem 'better_errors'
|
||||
gem 'binding_of_caller'
|
||||
gem 'letter_opener'
|
||||
gem 'quiet_assets'
|
||||
end
|
||||
|
||||
group :development, :test do
|
||||
gem 'haml-rails' # HTML templating language
|
||||
gem 'rspec-rails', '~> 3.1.0' # unit testing framework
|
||||
gem 'rspec-activemodel-mocks'
|
||||
gem 'byebug' # debugging
|
||||
gem 'database_cleaner', '~> 1.3.0'
|
||||
gem 'webrat' # provides HTML matchers for view tests
|
||||
gem 'factory_girl_rails', '~> 4.5.0' # for creating test data
|
||||
gem 'coveralls', require: false # coverage analysis
|
||||
gem 'capybara' # integration tests
|
||||
gem 'capybara-email' # integration tests for email
|
||||
gem 'poltergeist', '~> 1.5.1' # for headless JS testing
|
||||
gem 'i18n-tasks' # adds tests for finding missing and unused translations
|
||||
gem 'jasmine' # javascript unit testing
|
||||
gem 'd3-rails' # charting
|
||||
|
||||
end
|
||||
|
||||
group :travis do
|
||||
gem 'heroku-api'
|
||||
end
|
||||
|
||||
329
Gemfile.lock
329
Gemfile.lock
@@ -20,35 +20,39 @@ PATH
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actionmailer (3.2.13)
|
||||
actionpack (= 3.2.13)
|
||||
mail (~> 2.5.3)
|
||||
actionpack (3.2.13)
|
||||
activemodel (= 3.2.13)
|
||||
activesupport (= 3.2.13)
|
||||
builder (~> 3.0.0)
|
||||
actionmailer (4.1.9)
|
||||
actionpack (= 4.1.9)
|
||||
actionview (= 4.1.9)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
actionpack (4.1.9)
|
||||
actionview (= 4.1.9)
|
||||
activesupport (= 4.1.9)
|
||||
rack (~> 1.5.2)
|
||||
rack-test (~> 0.6.2)
|
||||
actionview (4.1.9)
|
||||
activesupport (= 4.1.9)
|
||||
builder (~> 3.1)
|
||||
erubis (~> 2.7.0)
|
||||
journey (~> 1.0.4)
|
||||
rack (~> 1.4.5)
|
||||
rack-cache (~> 1.2)
|
||||
rack-test (~> 0.6.1)
|
||||
sprockets (~> 2.2.1)
|
||||
activemodel (3.2.13)
|
||||
activesupport (= 3.2.13)
|
||||
builder (~> 3.0.0)
|
||||
activerecord (3.2.13)
|
||||
activemodel (= 3.2.13)
|
||||
activesupport (= 3.2.13)
|
||||
arel (~> 3.0.2)
|
||||
tzinfo (~> 0.3.29)
|
||||
activeresource (3.2.13)
|
||||
activemodel (= 3.2.13)
|
||||
activesupport (= 3.2.13)
|
||||
activesupport (3.2.13)
|
||||
i18n (= 0.6.1)
|
||||
multi_json (~> 1.0)
|
||||
active_link_to (1.0.2)
|
||||
actionpack
|
||||
activemodel (4.1.9)
|
||||
activesupport (= 4.1.9)
|
||||
builder (~> 3.1)
|
||||
activerecord (4.1.9)
|
||||
activemodel (= 4.1.9)
|
||||
activesupport (= 4.1.9)
|
||||
arel (~> 5.0.0)
|
||||
activesupport (4.1.9)
|
||||
i18n (~> 0.6, >= 0.6.9)
|
||||
json (~> 1.7, >= 1.7.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.1)
|
||||
tzinfo (~> 1.1)
|
||||
addressable (2.3.6)
|
||||
arel (3.0.3)
|
||||
arel (5.0.1.20140414130214)
|
||||
autoprefixer-rails (5.1.1)
|
||||
execjs
|
||||
json
|
||||
bcrypt (3.1.9)
|
||||
better_errors (2.0.0)
|
||||
coderay (>= 1.0.0)
|
||||
@@ -57,14 +61,19 @@ GEM
|
||||
binding_of_caller (0.7.2)
|
||||
debug_inspector (>= 0.0.1)
|
||||
bluecloth (2.2.0)
|
||||
bonsai-elasticsearch-rails (0.0.4)
|
||||
bootstrap-datepicker-rails (1.3.0.2)
|
||||
railties (>= 3.0)
|
||||
builder (3.0.4)
|
||||
bootstrap-sass (3.3.3)
|
||||
autoprefixer-rails (>= 5.0.0.1)
|
||||
sass (>= 3.2.19)
|
||||
bootstrap_form (2.2.0)
|
||||
builder (3.2.2)
|
||||
byebug (3.5.1)
|
||||
columnize (~> 0.8)
|
||||
debugger-linecache (~> 1.2)
|
||||
slop (~> 3.6)
|
||||
cancan (1.6.10)
|
||||
cancancan (1.9.2)
|
||||
capybara (2.4.4)
|
||||
mime-types (>= 1.16)
|
||||
nokogiri (>= 1.3.3)
|
||||
@@ -74,24 +83,38 @@ GEM
|
||||
capybara-email (2.4.0)
|
||||
capybara (~> 2.4)
|
||||
mail
|
||||
chunky_png (1.3.3)
|
||||
climate_control (0.0.3)
|
||||
activesupport (>= 3.0)
|
||||
cliver (0.3.2)
|
||||
cocaine (0.5.5)
|
||||
climate_control (>= 0.0.3, < 1.0)
|
||||
codemirror-rails (4.8)
|
||||
railties (>= 3.0, < 5)
|
||||
coderay (1.1.0)
|
||||
coffee-rails (3.2.2)
|
||||
coffee-rails (4.1.0)
|
||||
coffee-script (>= 2.2.0)
|
||||
railties (~> 3.2.0)
|
||||
railties (>= 4.0.0, < 5.0)
|
||||
coffee-script (2.3.0)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.8.0)
|
||||
columnize (0.8.9)
|
||||
columnize (0.9.0)
|
||||
comfortable_mexican_sofa (1.12.7)
|
||||
active_link_to (>= 1.0.0)
|
||||
bootstrap-sass (>= 3.2.0)
|
||||
bootstrap_form (>= 2.2.0)
|
||||
codemirror-rails (>= 3.0.0)
|
||||
coffee-rails (>= 3.1.0)
|
||||
haml-rails (>= 0.3.0)
|
||||
jquery-rails (>= 3.0.0)
|
||||
jquery-ui-rails (>= 5.0.0)
|
||||
kramdown (>= 1.0.0)
|
||||
paperclip (>= 4.0.0)
|
||||
plupload-rails (>= 1.2.1)
|
||||
rails (>= 4.0.0, < 5)
|
||||
rails-i18n (>= 4.0.0)
|
||||
sass-rails (>= 4.0.3)
|
||||
commonjs (0.2.7)
|
||||
compass (0.12.7)
|
||||
chunky_png (~> 1.2)
|
||||
fssm (>= 0.2.7)
|
||||
sass (~> 3.2.19)
|
||||
compass-rails (1.0.3)
|
||||
compass (>= 0.12.2, < 0.14)
|
||||
coveralls (0.7.1)
|
||||
multi_json (~> 1.3)
|
||||
rest-client
|
||||
@@ -106,51 +129,77 @@ GEM
|
||||
database_cleaner (1.3.0)
|
||||
debug_inspector (0.0.2)
|
||||
debugger-linecache (1.2.0)
|
||||
devise (3.2.4)
|
||||
devise (3.4.1)
|
||||
bcrypt (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
railties (>= 3.2.6, < 5)
|
||||
responders
|
||||
thread_safe (~> 0.1)
|
||||
warden (~> 1.2.3)
|
||||
diff-lcs (1.1.3)
|
||||
diff-lcs (1.2.5)
|
||||
docile (1.1.5)
|
||||
easy_translate (0.5.0)
|
||||
json
|
||||
thread
|
||||
thread_safe
|
||||
elasticsearch (1.0.6)
|
||||
elasticsearch-api (= 1.0.6)
|
||||
elasticsearch-transport (= 1.0.6)
|
||||
elasticsearch-api (1.0.6)
|
||||
multi_json
|
||||
elasticsearch-model (0.1.6)
|
||||
activesupport (> 3)
|
||||
elasticsearch (> 0.4)
|
||||
hashie
|
||||
elasticsearch-rails (0.1.6)
|
||||
elasticsearch-transport (1.0.6)
|
||||
faraday
|
||||
multi_json
|
||||
erubis (2.7.0)
|
||||
excon (0.43.0)
|
||||
execjs (2.2.2)
|
||||
factory_girl (4.5.0)
|
||||
activesupport (>= 3.0.0)
|
||||
factory_girl_rails (4.5.0)
|
||||
factory_girl (~> 4.5.0)
|
||||
railties (>= 3.0.0)
|
||||
faraday (0.9.1)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
figaro (1.0.0)
|
||||
thor (~> 0.14)
|
||||
flickraw (0.9.8)
|
||||
friendly_id (4.0.10.1)
|
||||
activerecord (>= 3.0, < 4.0)
|
||||
fssm (0.2.10)
|
||||
friendly_id (5.0.4)
|
||||
activerecord (>= 4.0.0)
|
||||
gibbon (1.1.4)
|
||||
httparty
|
||||
multi_json (>= 1.3.4)
|
||||
gravatar-ultimate (2.0.0)
|
||||
activesupport (>= 2.3.14)
|
||||
rack
|
||||
haml (4.0.5)
|
||||
haml (4.1.0.beta.1)
|
||||
tilt
|
||||
haml-rails (0.4)
|
||||
actionpack (>= 3.1, < 4.1)
|
||||
activesupport (>= 3.1, < 4.1)
|
||||
haml (>= 3.1, < 4.1)
|
||||
railties (>= 3.1, < 4.1)
|
||||
haml-rails (0.6.0)
|
||||
actionpack (>= 4.0.1)
|
||||
activesupport (>= 4.0.1)
|
||||
haml (>= 3.1, < 5.0)
|
||||
html2haml (>= 1.0.1)
|
||||
railties (>= 4.0.1)
|
||||
hashie (3.3.2)
|
||||
heroku-api (0.3.22)
|
||||
excon (~> 0.38)
|
||||
multi_json (~> 1.8)
|
||||
highline (1.6.21)
|
||||
hike (1.2.3)
|
||||
httparty (0.11.0)
|
||||
multi_json (~> 1.0)
|
||||
hpricot (0.8.6)
|
||||
html2haml (1.0.1)
|
||||
erubis (~> 2.7.0)
|
||||
haml (>= 4.0.0.rc.1)
|
||||
hpricot (~> 0.8.6)
|
||||
ruby_parser (~> 3.1.1)
|
||||
httparty (0.13.3)
|
||||
json (~> 1.8)
|
||||
multi_xml (>= 0.5.2)
|
||||
i18n (0.6.1)
|
||||
i18n (0.7.0)
|
||||
i18n-tasks (0.7.8)
|
||||
activesupport
|
||||
easy_translate (>= 0.5.0)
|
||||
@@ -160,6 +209,7 @@ GEM
|
||||
slop (>= 3.5.0)
|
||||
term-ansicolor
|
||||
terminal-table
|
||||
<<<<<<< HEAD
|
||||
jasmine (2.1.0)
|
||||
jasmine-core (~> 2.1.0)
|
||||
phantomjs
|
||||
@@ -167,16 +217,19 @@ GEM
|
||||
rake
|
||||
jasmine-core (2.1.2)
|
||||
journey (1.0.4)
|
||||
=======
|
||||
>>>>>>> dev
|
||||
jquery-rails (3.1.2)
|
||||
railties (>= 3.0, < 5.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
jquery-ui-rails (4.1.2)
|
||||
railties (>= 3.1.0)
|
||||
jquery-ui-rails (5.0.3)
|
||||
railties (>= 3.2.16)
|
||||
js-routes (0.9.9)
|
||||
railties (>= 3.2)
|
||||
sprockets-rails
|
||||
json (1.7.7)
|
||||
json (1.8.2)
|
||||
kgio (2.9.2)
|
||||
kramdown (1.5.0)
|
||||
launchy (2.4.3)
|
||||
addressable (~> 2.3)
|
||||
leaflet-markercluster-rails (0.7.0)
|
||||
@@ -189,20 +242,21 @@ GEM
|
||||
less (~> 2.5.0)
|
||||
less-rails-bootstrap (3.2.0)
|
||||
less-rails (~> 2.5.0)
|
||||
letter_opener (1.2.0)
|
||||
letter_opener (1.3.0)
|
||||
launchy (~> 2.2)
|
||||
libv8 (3.16.14.7)
|
||||
mail (2.5.4)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
mail (2.6.3)
|
||||
mime-types (>= 1.16, < 3)
|
||||
memcachier (0.0.2)
|
||||
method_source (0.8.2)
|
||||
mime-types (1.25.1)
|
||||
mime-types (2.4.3)
|
||||
mini_portile (0.6.1)
|
||||
minitest (5.5.1)
|
||||
multi_json (1.10.1)
|
||||
multi_xml (0.5.5)
|
||||
netrc (0.8.0)
|
||||
newrelic_rpm (3.9.7.266)
|
||||
multipart-post (2.0.0)
|
||||
netrc (0.10.0)
|
||||
newrelic_rpm (3.9.8.273)
|
||||
nokogiri (1.6.5)
|
||||
mini_portile (~> 0.6.0)
|
||||
oauth (0.4.7)
|
||||
@@ -218,82 +272,108 @@ GEM
|
||||
multi_json (~> 1.3)
|
||||
omniauth-oauth (~> 1.0)
|
||||
orm_adapter (0.5.0)
|
||||
paperclip (4.2.1)
|
||||
activemodel (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
cocaine (~> 0.5.3)
|
||||
mime-types
|
||||
pg (0.17.1)
|
||||
<<<<<<< HEAD
|
||||
phantomjs (1.9.7.1)
|
||||
=======
|
||||
plupload-rails (1.2.1)
|
||||
rails (>= 3.1)
|
||||
>>>>>>> dev
|
||||
poltergeist (1.5.1)
|
||||
capybara (~> 2.1)
|
||||
cliver (~> 0.3.1)
|
||||
multi_json (~> 1.0)
|
||||
websocket-driver (>= 0.2.0)
|
||||
polyglot (0.3.5)
|
||||
pry (0.10.1)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
slop (~> 3.4)
|
||||
rack (1.4.5)
|
||||
rack-cache (1.2)
|
||||
rack (>= 0.4)
|
||||
rack-ssl (1.3.4)
|
||||
rack
|
||||
rack-test (0.6.2)
|
||||
quiet_assets (1.1.0)
|
||||
railties (>= 3.1, < 5.0)
|
||||
rack (1.5.2)
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rails (3.2.13)
|
||||
actionmailer (= 3.2.13)
|
||||
actionpack (= 3.2.13)
|
||||
activerecord (= 3.2.13)
|
||||
activeresource (= 3.2.13)
|
||||
activesupport (= 3.2.13)
|
||||
bundler (~> 1.0)
|
||||
railties (= 3.2.13)
|
||||
rails (4.1.9)
|
||||
actionmailer (= 4.1.9)
|
||||
actionpack (= 4.1.9)
|
||||
actionview (= 4.1.9)
|
||||
activemodel (= 4.1.9)
|
||||
activerecord (= 4.1.9)
|
||||
activesupport (= 4.1.9)
|
||||
bundler (>= 1.3.0, < 2.0)
|
||||
railties (= 4.1.9)
|
||||
sprockets-rails (~> 2.0)
|
||||
rails-i18n (4.0.3)
|
||||
i18n (~> 0.6)
|
||||
railties (~> 4.0)
|
||||
rails_12factor (0.0.3)
|
||||
rails_serve_static_assets
|
||||
rails_stdout_logging
|
||||
rails_serve_static_assets (0.0.2)
|
||||
rails_stdout_logging (0.0.3)
|
||||
railties (3.2.13)
|
||||
actionpack (= 3.2.13)
|
||||
activesupport (= 3.2.13)
|
||||
rack-ssl (~> 1.3.2)
|
||||
railties (4.1.9)
|
||||
actionpack (= 4.1.9)
|
||||
activesupport (= 4.1.9)
|
||||
rake (>= 0.8.7)
|
||||
rdoc (~> 3.4)
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
raindrops (0.13.0)
|
||||
rake (10.4.0)
|
||||
rdoc (3.12.2)
|
||||
json (~> 1.4)
|
||||
rake (10.4.2)
|
||||
ref (1.0.5)
|
||||
responders (1.1.2)
|
||||
railties (>= 3.2, < 4.2)
|
||||
rest-client (1.7.2)
|
||||
mime-types (>= 1.16, < 3.0)
|
||||
netrc (~> 0.7)
|
||||
rspec-core (2.12.2)
|
||||
rspec-expectations (2.12.1)
|
||||
diff-lcs (~> 1.1.3)
|
||||
rspec-mocks (2.12.2)
|
||||
rspec-rails (2.12.2)
|
||||
rspec-activemodel-mocks (1.0.1)
|
||||
activemodel (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
rspec-mocks (>= 2.99, < 4.0)
|
||||
rspec-core (3.1.7)
|
||||
rspec-support (~> 3.1.0)
|
||||
rspec-expectations (3.1.2)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.1.0)
|
||||
rspec-mocks (3.1.3)
|
||||
rspec-support (~> 3.1.0)
|
||||
rspec-rails (3.1.0)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
rspec-core (~> 2.12.0)
|
||||
rspec-expectations (~> 2.12.0)
|
||||
rspec-mocks (~> 2.12.0)
|
||||
rspec-core (~> 3.1.0)
|
||||
rspec-expectations (~> 3.1.0)
|
||||
rspec-mocks (~> 3.1.0)
|
||||
rspec-support (~> 3.1.0)
|
||||
rspec-support (3.1.2)
|
||||
ruby-units (1.4.5)
|
||||
ruby_parser (3.1.3)
|
||||
sexp_processor (~> 4.1)
|
||||
sass (3.2.19)
|
||||
sass-rails (3.2.6)
|
||||
railties (~> 3.2.0)
|
||||
sass (>= 3.1.10)
|
||||
tilt (~> 1.3)
|
||||
sass-rails (4.0.5)
|
||||
railties (>= 4.0.0, < 5.0)
|
||||
sass (~> 3.2.2)
|
||||
sprockets (~> 2.8, < 3.0)
|
||||
sprockets-rails (~> 2.0)
|
||||
sexp_processor (4.4.4)
|
||||
simplecov (0.9.1)
|
||||
docile (~> 1.1.0)
|
||||
multi_json (~> 1.0)
|
||||
simplecov-html (~> 0.8.0)
|
||||
simplecov-html (0.8.0)
|
||||
slop (3.6.0)
|
||||
sprockets (2.2.3)
|
||||
sprockets (2.12.3)
|
||||
hike (~> 1.2)
|
||||
multi_json (~> 1.0)
|
||||
rack (~> 1.0)
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
sprockets-rails (0.0.1)
|
||||
sprockets (>= 1.0.2)
|
||||
sprockets-rails (2.2.2)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
term-ansicolor (1.3.0)
|
||||
tins (~> 1.0)
|
||||
terminal-table (1.4.5)
|
||||
@@ -305,13 +385,11 @@ GEM
|
||||
thread_safe (0.3.4)
|
||||
tilt (1.4.1)
|
||||
tins (1.3.3)
|
||||
treetop (1.4.15)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
tzinfo (0.3.42)
|
||||
uglifier (2.2.1)
|
||||
tzinfo (1.2.2)
|
||||
thread_safe (~> 0.1)
|
||||
uglifier (2.5.3)
|
||||
execjs (>= 0.3.0)
|
||||
multi_json (~> 1.0, >= 1.0.2)
|
||||
json (>= 1.8.0)
|
||||
unicorn (4.8.3)
|
||||
kgio (~> 2.6)
|
||||
rack
|
||||
@@ -322,7 +400,9 @@ GEM
|
||||
nokogiri (>= 1.2.0)
|
||||
rack (>= 1.0)
|
||||
rack-test (>= 0.5.3)
|
||||
websocket-driver (0.4.0)
|
||||
websocket-driver (0.5.0)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.0)
|
||||
will_paginate (3.0.7)
|
||||
xpath (2.0.0)
|
||||
nokogiri (~> 1.3)
|
||||
@@ -336,35 +416,38 @@ DEPENDENCIES
|
||||
better_errors
|
||||
binding_of_caller
|
||||
bluecloth
|
||||
bonsai-elasticsearch-rails
|
||||
bootstrap-datepicker-rails
|
||||
bundler (>= 1.1.5)
|
||||
byebug
|
||||
cancan
|
||||
cancancan (~> 1.9)
|
||||
capybara
|
||||
capybara-email
|
||||
coffee-rails (~> 3.2.1)
|
||||
compass-rails (~> 1.0.3)
|
||||
coffee-rails (~> 4.1.0)
|
||||
comfortable_mexican_sofa (~> 1.12.0)
|
||||
coveralls
|
||||
csv_shaper
|
||||
d3-rails
|
||||
dalli
|
||||
database_cleaner (~> 1.3.0)
|
||||
devise (~> 3.2.0)
|
||||
factory_girl_rails (~> 4.0)
|
||||
devise (~> 3.4.1)
|
||||
elasticsearch-model
|
||||
elasticsearch-rails
|
||||
factory_girl_rails (~> 4.5.0)
|
||||
figaro
|
||||
flickraw
|
||||
friendly_id (~> 4.0.10)
|
||||
friendly_id (~> 5.0.4)
|
||||
geocoder!
|
||||
gibbon
|
||||
gravatar-ultimate
|
||||
haml
|
||||
haml-rails
|
||||
heroku-api
|
||||
i18n-tasks
|
||||
jasmine
|
||||
jquery-rails
|
||||
jquery-ui-rails
|
||||
jquery-ui-rails (~> 5.0.2)
|
||||
js-routes
|
||||
json (~> 1.7.7)
|
||||
leaflet-markercluster-rails
|
||||
leaflet-rails
|
||||
less (~> 2.5.0)
|
||||
@@ -380,14 +463,16 @@ DEPENDENCIES
|
||||
pg
|
||||
poltergeist (~> 1.5.1)
|
||||
pry
|
||||
rack (~> 1.4.5)
|
||||
rails (= 3.2.13)
|
||||
quiet_assets
|
||||
rails (= 4.1.9)
|
||||
rails_12factor
|
||||
rake (>= 10.0.0)
|
||||
rspec-rails (~> 2.12.1)
|
||||
sass-rails (~> 3.2.3)
|
||||
rspec-activemodel-mocks
|
||||
rspec-rails (~> 3.1.0)
|
||||
ruby-units
|
||||
sass-rails (~> 4.0.4)
|
||||
therubyracer (~> 0.12)
|
||||
uglifier (>= 1.0.3)
|
||||
uglifier (~> 2.5.3)
|
||||
unicorn
|
||||
webrat
|
||||
will_paginate (~> 3.0)
|
||||
|
||||
36
README.md
36
README.md
@@ -16,18 +16,42 @@ encourage participation from people of all backgrounds and skill levels.
|
||||
|
||||
## Important links
|
||||
|
||||
* [Wiki](http://wiki.growstuff.org/) (general documentation)
|
||||
* [Task tracker](http://tracker.growstuff.org/) (recent and upcoming work, bugs, etc)
|
||||
* [Issues](http://github.com/Growstuff/growstuff/issues) (features we're
|
||||
working on, known bugs, etc)
|
||||
* [Discussion forums](http://wiki.growstuff.org/index.php/Discussion_forums) (mailing lists, IRC, etc)
|
||||
* [Wiki](http://wiki.growstuff.org/) (general documentation)
|
||||
|
||||
## For developers
|
||||
## For coders
|
||||
|
||||
Growstuff is built in Ruby on Rails and also uses JavaScript for
|
||||
frontend features. We welcome contributions -- see
|
||||
[CONTRIBUTING](CONTRIBUTING.md) for details.
|
||||
|
||||
* Start by looking at our [task tracker](http://tracker.growstuff.org/) for something to work on.
|
||||
* Drop in to one of our [discussion forums](http://wiki.growstuff.org/index.php/Discussion_forums) to talk to our team about it.
|
||||
* To set up your development environment, see [Getting started](http://wiki.growstuff.org/index.php/Development/Getting_Started).
|
||||
* We encourage [pair programming](http://wiki.growstuff.org/index.php/Pairing), especially for newer developers.
|
||||
* We encourage [pair programming](http://wiki.growstuff.org/index.php/Pairing), especially for newer developers. [Find a pair programming partner.](http://talk.growstuff.org/t/find-a-pair-programming-partner/13)
|
||||
* Drop in to one of our [discussion forums](http://wiki.growstuff.org/index.php/Discussion_forums) to chat to other developers, get help, etc.
|
||||
* You may also be interested in our [API](http://wiki.growstuff.org/index.php/API).
|
||||
|
||||
## For designers, writers, researchers, data wranglers, and other contributors
|
||||
|
||||
There are heaps of ways to get involved and contribute no matter what
|
||||
your skills and interests.
|
||||
|
||||
You might like to check out:
|
||||
|
||||
* The [Get Involved](http://wiki.growstuff.org/index.php/Get_involved)
|
||||
page on our wiki, which has lots of detail for different areas
|
||||
* [Growstuff Talk](http://talk.growstuff.org/) especially the [Idea category](http://talk.growstuff.org/c/idea)
|
||||
|
||||
Here on Github, you might find these useful:
|
||||
|
||||
* [needs: design](https://github.com/Growstuff/growstuff/labels/needs:%20design) - tasks requiring high-level design
|
||||
* [needs: visual design](https://github.com/Growstuff/growstuff/labels/needs:%20visual design) - tasks requiring visual/graphical design
|
||||
* [needs: documentation](https://github.com/Growstuff/growstuff/labels/needs:%20documentation)
|
||||
* [needs: data](https://github.com/Growstuff/growstuff/labels/needs:%20data) - tasks requiring data entry, data design, data import, or similar
|
||||
|
||||
Feel free to comment on any of the issues you find there, or open up a broader conversation on [Growstuff Talk](http://talk.growstuff.org).
|
||||
|
||||
## Contact
|
||||
|
||||
For more information about this project, contact [info@growstuff.org](mailto:info@growstuff.org).
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 572 B After Width: | Height: | Size: 613 B |
@@ -15,7 +15,7 @@
|
||||
//= require js-routes
|
||||
//= require jquery
|
||||
//= require jquery_ujs
|
||||
//= require jquery.ui.autocomplete
|
||||
//= require jquery-ui/autocomplete
|
||||
//= require twitter/bootstrap
|
||||
//= require_tree .
|
||||
//= require bootstrap-datepicker
|
||||
//= require bootstrap-datepicker
|
||||
|
||||
1
app/assets/javascripts/comfy/admin/cms/custom.js.coffee
Normal file
1
app/assets/javascripts/comfy/admin/cms/custom.js.coffee
Normal file
@@ -0,0 +1 @@
|
||||
# Custom JS for the admin area
|
||||
@@ -3,7 +3,7 @@
|
||||
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
||||
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
||||
*= require_self
|
||||
*= require jquery.ui.autocomplete
|
||||
*= require jquery-ui/autocomplete
|
||||
*= require bootstrap-datepicker
|
||||
*= require leaflet
|
||||
*= require leaflet.markercluster
|
||||
|
||||
1
app/assets/stylesheets/comfy/admin/cms/custom.sass
Normal file
1
app/assets/stylesheets/comfy/admin/cms/custom.sass
Normal file
@@ -0,0 +1 @@
|
||||
// custom CSS for admin area
|
||||
@@ -122,7 +122,7 @@ p.stats {
|
||||
color: @brown;
|
||||
}
|
||||
|
||||
.crop-thumbnail {
|
||||
.photo-thumbnail {
|
||||
position:relative;
|
||||
padding:0;
|
||||
img {
|
||||
@@ -149,33 +149,55 @@ p.stats {
|
||||
}
|
||||
}
|
||||
|
||||
.member-thumbnail {
|
||||
img {
|
||||
height: 85px;
|
||||
width: 85px;
|
||||
max-width: 85px
|
||||
}
|
||||
}
|
||||
|
||||
.thumbnail {
|
||||
border: none;
|
||||
text-align: center;
|
||||
margin-bottom: 1.5em;
|
||||
|
||||
.scientific-name small, .crop-name a {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 1em;
|
||||
padding-bottom: 2px;
|
||||
|
||||
.member-thumbnail {
|
||||
text-align: left;
|
||||
img {
|
||||
height: 85px;
|
||||
width: 85px;
|
||||
max-width: 85px
|
||||
}
|
||||
}
|
||||
|
||||
.crop-name a {
|
||||
padding-top: 2px;
|
||||
}
|
||||
.crop-thumbnail {
|
||||
height: 220px;
|
||||
.cropinfo {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
white-space: nowrap;
|
||||
line-height: 1em;
|
||||
padding-bottom: 2px;
|
||||
|
||||
.scientific-name small {
|
||||
margin-bottom: -2px;
|
||||
.cropname {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.scientificname {
|
||||
font-size: small;
|
||||
font-style: italic;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.plantingcount {
|
||||
font-size: small;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.crop-name a {
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.scientific-name small {
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,31 +214,48 @@ li.crop-hierarchy {
|
||||
margin: 40px 0px 0px 0px !important;
|
||||
}
|
||||
|
||||
// navbar centering
|
||||
footer .navbar .nav {
|
||||
float: none;
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
/* ie7 fix */
|
||||
*zoom: 1;
|
||||
/* hasLayout ie7 trigger */
|
||||
vertical-align: top;
|
||||
> li {
|
||||
float: none;
|
||||
display: inline-block;
|
||||
*display: inline;
|
||||
/* ie7 fix */
|
||||
*zoom: 1;
|
||||
/* hasLayout ie7 trigger */
|
||||
vertical-align: top;
|
||||
// footer
|
||||
|
||||
footer {
|
||||
#contact, #about-growstuff, #policies {
|
||||
text-align: left;
|
||||
padding-top: 1em;
|
||||
padding-bottom: 2em;
|
||||
ul {
|
||||
list-style-type: none;
|
||||
list-style-position: outside;
|
||||
padding-left: 0px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
a {
|
||||
color: @navbar-default-link-color;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
color: @navbar-default-link-hover-color;
|
||||
}
|
||||
a:active {
|
||||
color: @navbar-default-link-active-color;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-bottom.navbar {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-bottom.navbar {
|
||||
text-align: center;
|
||||
border-radius: 0;
|
||||
// ensure footer is pushed to bottom of browser window
|
||||
|
||||
#maincontainer {
|
||||
min-height: 80%;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
.crop-image, .member-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -244,6 +283,12 @@ footer .navbar .nav {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.alert {
|
||||
a {
|
||||
font-weight: 800;
|
||||
}
|
||||
}
|
||||
|
||||
// Overrides applying only to mobile view. This must be at the end of the overrides file.
|
||||
|
||||
@media only screen and (max-width: 767px) {
|
||||
@@ -261,3 +306,13 @@ footer .navbar .nav {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/* override "info" alert boxes to be green, not blue, on Growstuff */
|
||||
@state-info-text: darken(@green, 10%);
|
||||
@state-info-bg: lighten(@green, 50%);
|
||||
|
||||
/* and set "success" to be the same, as it was just very slightly
|
||||
* different because the default bootstrap green is slightly different
|
||||
* from ours */
|
||||
@state-success-text: darken(@green, 10%);
|
||||
@state-success-bg: lighten(@green, 50%);
|
||||
|
||||
@@ -36,7 +36,7 @@ class AccountTypesController < ApplicationController
|
||||
|
||||
# POST /account_types
|
||||
def create
|
||||
@account_type = AccountType.new(params[:account_type])
|
||||
@account_type = AccountType.new(account_type_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @account_type.save
|
||||
@@ -52,7 +52,7 @@ class AccountTypesController < ApplicationController
|
||||
@account_type = AccountType.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
if @account_type.update_attributes(params[:account_type])
|
||||
if @account_type.update(account_type_params)
|
||||
format.html { redirect_to @account_type, notice: 'Account type was successfully updated.' }
|
||||
else
|
||||
format.html { render action: "edit" }
|
||||
@@ -69,4 +69,10 @@ class AccountTypesController < ApplicationController
|
||||
format.html { redirect_to account_types_url, notice: 'Account type was successfully deleted.' }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def account_type_params
|
||||
params.require(:account_type).permit(:is_paid, :is_permanent_paid, :name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,7 +30,7 @@ class AccountsController < ApplicationController
|
||||
@account = Account.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
if @account.update_attributes(params[:account])
|
||||
if @account.update(params[:account])
|
||||
format.html { redirect_to @account, notice: 'Account detail was successfully updated.' }
|
||||
else
|
||||
format.html { render action: "edit" }
|
||||
@@ -38,4 +38,10 @@ class AccountsController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def account_params
|
||||
params.require(:account).permit(:account_type_id, :member_id, :paid_until)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -45,7 +45,7 @@ class AlternateNamesController < ApplicationController
|
||||
# POST /alternate_names.json
|
||||
def create
|
||||
params[:alternate_name][:creator_id] = current_member.id
|
||||
@alternate_name = AlternateName.new(params[:alternate_name])
|
||||
@alternate_name = AlternateName.new(alternate_name_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @alternate_name.save
|
||||
@@ -64,7 +64,7 @@ class AlternateNamesController < ApplicationController
|
||||
@alternate_name = AlternateName.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
if @alternate_name.update_attributes(params[:alternate_name])
|
||||
if @alternate_name.update(alternate_name_params)
|
||||
format.html { redirect_to @alternate_name.crop, notice: 'Alternate name was successfully updated.' }
|
||||
format.json { head :no_content }
|
||||
else
|
||||
@@ -88,4 +88,10 @@ class AlternateNamesController < ApplicationController
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def alternate_name_params
|
||||
params.require(:alternate_name).permit(:crop_id, :name, :creator_id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -43,4 +43,36 @@ class ApplicationController < ActionController::Base
|
||||
I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
|
||||
end
|
||||
|
||||
before_action :configure_permitted_parameters, if: :devise_controller?
|
||||
|
||||
protected
|
||||
|
||||
def configure_permitted_parameters
|
||||
devise_parameter_sanitizer.for(:sign_up) do |member|
|
||||
member.permit(:login_name, :email, :password, :password_confirmation,
|
||||
:remember_me, :login,
|
||||
# terms of service
|
||||
:tos_agreement,
|
||||
# profile stuff
|
||||
:bio, :location, :latitude, :longitude,
|
||||
# email settings
|
||||
:show_email, :newsletter, :send_notification_email, :send_planting_reminder
|
||||
)
|
||||
end
|
||||
|
||||
devise_parameter_sanitizer.for(:account_update) do |member|
|
||||
member.permit(:login_name, :email, :password, :password_confirmation,
|
||||
:remember_me, :login,
|
||||
# terms of service
|
||||
:tos_agreement,
|
||||
# profile stuff
|
||||
:bio, :location, :latitude, :longitude,
|
||||
# email settings
|
||||
:show_email, :newsletter, :send_notification_email, :send_planting_reminder,
|
||||
#update password
|
||||
:current_password
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -2,15 +2,6 @@ class AuthenticationsController < ApplicationController
|
||||
before_filter :authenticate_member!
|
||||
load_and_authorize_resource
|
||||
|
||||
# GET /authentications
|
||||
def index
|
||||
@authentications = current_member.authentications if member_signed_in?
|
||||
|
||||
respond_to do |format|
|
||||
format.html # index.html.erb
|
||||
end
|
||||
end
|
||||
|
||||
# POST /authentications
|
||||
def create
|
||||
auth = request.env['omniauth.auth']
|
||||
@@ -27,12 +18,17 @@ class AuthenticationsController < ApplicationController
|
||||
name = auth['info']['name']
|
||||
end
|
||||
|
||||
@authentication = current_member.authentications.find_or_create_by_provider_and_uid(
|
||||
:provider => auth['provider'],
|
||||
:uid => auth['uid'],
|
||||
@authentication = current_member.authentications
|
||||
.create_with(
|
||||
:name => name,
|
||||
:token => auth['credentials']['token'],
|
||||
:secret => auth['credentials']['secret'])
|
||||
:secret => auth['credentials']['secret']
|
||||
)
|
||||
.find_or_create_by(
|
||||
:provider => auth['provider'],
|
||||
:uid => auth['uid'],
|
||||
:name => name)
|
||||
|
||||
flash[:notice] = "Authentication successful."
|
||||
else
|
||||
flash[:notice] = "Authentication failed."
|
||||
|
||||
@@ -2,8 +2,6 @@ class CommentsController < ApplicationController
|
||||
before_filter :authenticate_member!, :except => [:index, :show]
|
||||
load_and_authorize_resource
|
||||
|
||||
cache_sweeper :comment_sweeper
|
||||
|
||||
# GET /comments
|
||||
# GET /comments.json
|
||||
def index
|
||||
@@ -55,11 +53,11 @@ class CommentsController < ApplicationController
|
||||
# POST /comments.json
|
||||
def create
|
||||
params[:comment][:author_id] = current_member.id
|
||||
@comment = Comment.new(params[:comment])
|
||||
@comment = Comment.new(comment_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @comment.save
|
||||
format.html { redirect_to @comment.post, notice: 'Comment was successfully created.' }
|
||||
format.html { redirect_to @comment.post, notice: "Comment was successfully created." }
|
||||
format.json { render json: @comment, status: :created, location: @comment }
|
||||
else
|
||||
format.html { render action: "new" }
|
||||
@@ -79,7 +77,7 @@ class CommentsController < ApplicationController
|
||||
params[:comment].delete("author_id")
|
||||
|
||||
respond_to do |format|
|
||||
if @comment.update_attributes(params[:comment])
|
||||
if @comment.update(comment_params)
|
||||
format.html { redirect_to @comment.post, notice: 'Comment was successfully updated.' }
|
||||
format.json { head :no_content }
|
||||
else
|
||||
@@ -101,4 +99,10 @@ class CommentsController < ApplicationController
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def comment_params
|
||||
params.require(:comment).permit(:author_id, :body, :post_id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,18 +3,18 @@ class CropsController < ApplicationController
|
||||
load_and_authorize_resource
|
||||
skip_authorize_resource :only => [:hierarchy, :search]
|
||||
|
||||
cache_sweeper :crop_sweeper
|
||||
|
||||
# GET /crops
|
||||
# GET /crops.json
|
||||
def index
|
||||
@sort = params[:sort]
|
||||
if @sort == 'alpha'
|
||||
# alphabetical order
|
||||
@crops = Crop.includes(:scientific_names, {:plantings => :photos}).paginate(:page => params[:page])
|
||||
@crops = Crop.includes(:scientific_names, {:plantings => :photos})
|
||||
@paginated_crops = @crops.paginate(:page => params[:page])
|
||||
else
|
||||
# default to sorting by popularity
|
||||
@crops = Crop.popular.includes(:scientific_names, {:plantings => :photos}).paginate(:page => params[:page])
|
||||
@crops = Crop.popular.includes(:scientific_names, {:plantings => :photos})
|
||||
@paginated_crops = @crops.paginate(:page => params[:page])
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
@@ -34,7 +34,18 @@ class CropsController < ApplicationController
|
||||
|
||||
# GET /crops/wrangle
|
||||
def wrangle
|
||||
@crops = Crop.recent.paginate(:page => params[:page])
|
||||
@approval_status = params[:approval_status]
|
||||
case @approval_status
|
||||
when "pending"
|
||||
@crops = Crop.pending_approval
|
||||
when "rejected"
|
||||
@crops = Crop.rejected
|
||||
else
|
||||
@crops = Crop.recent
|
||||
end
|
||||
|
||||
@crops = @crops.paginate(:page => params[:page])
|
||||
|
||||
@crop_wranglers = Role.crop_wranglers
|
||||
respond_to do |format|
|
||||
format.html
|
||||
@@ -52,17 +63,17 @@ class CropsController < ApplicationController
|
||||
# GET /crops/search
|
||||
def search
|
||||
@search = params[:search]
|
||||
@exact_match = Crop.find_by_name(params[:search])
|
||||
|
||||
@partial_matches = Crop.search(params[:search])
|
||||
# exclude exact match from partial match list
|
||||
@partial_matches.reject!{ |r| @exact_match && r.eql?(@exact_match) }
|
||||
|
||||
@fuzzy = Crop.search(params[:term])
|
||||
@all_matches = Crop.search(@search)
|
||||
@paginated_matches = @all_matches.paginate(:page => params[:page])
|
||||
exact_match = Crop.find_by_name(@search)
|
||||
if exact_match
|
||||
@all_matches.delete(exact_match)
|
||||
@all_matches.unshift(exact_match)
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json { render :json => @fuzzy }
|
||||
format.json { render :json => Crop.search(@search) }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -98,17 +109,35 @@ class CropsController < ApplicationController
|
||||
# GET /crops/1/edit
|
||||
def edit
|
||||
@crop = Crop.find(params[:id])
|
||||
|
||||
(3 - @crop.scientific_names.length).times do
|
||||
@crop.scientific_names.build
|
||||
end
|
||||
end
|
||||
|
||||
# POST /crops
|
||||
# POST /crops.json
|
||||
def create
|
||||
params[:crop][:creator_id] = current_member.id
|
||||
@crop = Crop.new(params[:crop])
|
||||
@crop = Crop.new(crop_params)
|
||||
|
||||
if current_member.has_role? :crop_wrangler
|
||||
@crop.creator = current_member
|
||||
success_msg = "Crop was successfully created."
|
||||
else
|
||||
@crop.requester = current_member
|
||||
@crop.approval_status = "pending"
|
||||
success_msg = "Crop was successfully requested."
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
if @crop.save
|
||||
format.html { redirect_to @crop, notice: 'Crop was successfully created.' }
|
||||
unless current_member.has_role? :crop_wrangler
|
||||
Role.crop_wranglers.each do |w|
|
||||
Notifier.new_crop_request(w, @crop).deliver!
|
||||
end
|
||||
end
|
||||
|
||||
format.html { redirect_to @crop, notice: success_msg }
|
||||
format.json { render json: @crop, status: :created, location: @crop }
|
||||
else
|
||||
format.html { render action: "new" }
|
||||
@@ -122,8 +151,18 @@ class CropsController < ApplicationController
|
||||
def update
|
||||
@crop = Crop.find(params[:id])
|
||||
|
||||
previous_status = @crop.approval_status
|
||||
|
||||
@crop.creator = current_member if previous_status == "pending"
|
||||
|
||||
respond_to do |format|
|
||||
if @crop.update_attributes(params[:crop])
|
||||
if @crop.update(crop_params)
|
||||
if previous_status == "pending"
|
||||
requester = @crop.requester
|
||||
new_status = @crop.approval_status
|
||||
Notifier.crop_request_approved(requester, @crop).deliver! if new_status == "approved"
|
||||
Notifier.crop_request_rejected(requester, @crop).deliver! if new_status == "rejected"
|
||||
end
|
||||
format.html { redirect_to @crop, notice: 'Crop was successfully updated.' }
|
||||
format.json { head :no_content }
|
||||
else
|
||||
@@ -144,4 +183,10 @@ class CropsController < ApplicationController
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def crop_params
|
||||
params.require(:crop).permit(:en_wikipedia_url, :name, :parent_id, :creator_id, :approval_status, :request_notes, :reason_for_rejection, :rejection_notes, :scientific_names_attributes => [:scientific_name, :_destroy, :id])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
class FollowsController < ApplicationController
|
||||
before_filter :authenticate_member!
|
||||
load_and_authorize_resource
|
||||
skip_load_resource :only => :create
|
||||
|
||||
# POST /follows
|
||||
def create
|
||||
@follow = current_member.follows.build(:followed_id => params[:followed_id])
|
||||
|
||||
@follow = current_member.follows.build(:followed_id => follow_params[:followed_id])
|
||||
|
||||
if @follow.save
|
||||
flash[:notice] = "Followed #{ @follow.followed.login_name }"
|
||||
@@ -15,11 +19,17 @@ class FollowsController < ApplicationController
|
||||
|
||||
# DELETE /follows/1
|
||||
def destroy
|
||||
@follow = current_member.follows.find(params[:id])
|
||||
@follow = current_member.follows.find(follow_params[:id])
|
||||
unfollowed_name = @follow.followed.login_name
|
||||
@follow.destroy
|
||||
|
||||
flash[:notice] = "Unfollowed #{ unfollowed_name }"
|
||||
redirect_to root_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def follow_params
|
||||
params.permit(:id, :followed_id, :follower_id, :authenticity_token, :_method)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
class ForumsController < ApplicationController
|
||||
load_and_authorize_resource
|
||||
|
||||
cache_sweeper :forum_sweeper
|
||||
|
||||
# GET /forums
|
||||
# GET /forums.json
|
||||
def index
|
||||
@@ -44,7 +42,7 @@ class ForumsController < ApplicationController
|
||||
# POST /forums
|
||||
# POST /forums.json
|
||||
def create
|
||||
@forum = Forum.new(params[:forum])
|
||||
@forum = Forum.new(forum_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @forum.save
|
||||
@@ -63,7 +61,7 @@ class ForumsController < ApplicationController
|
||||
@forum = Forum.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
if @forum.update_attributes(params[:forum])
|
||||
if @forum.update(forum_params)
|
||||
format.html { redirect_to @forum, notice: 'Forum was successfully updated.' }
|
||||
format.json { head :no_content }
|
||||
else
|
||||
@@ -84,4 +82,10 @@ class ForumsController < ApplicationController
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def forum_params
|
||||
params.require(:forum).permit(:description, :name, :owner_id, :slug)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
class GardensController < ApplicationController
|
||||
before_filter :authenticate_member!, :except => [:index, :show]
|
||||
load_and_authorize_resource
|
||||
|
||||
cache_sweeper :garden_sweeper
|
||||
|
||||
|
||||
# GET /gardens
|
||||
# GET /gardens.json
|
||||
@@ -50,12 +49,13 @@ class GardensController < ApplicationController
|
||||
# POST /gardens.json
|
||||
def create
|
||||
params[:garden][:owner_id] = current_member.id
|
||||
@garden = Garden.new(params[:garden])
|
||||
@garden = Garden.new(garden_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @garden.save
|
||||
format.html { redirect_to @garden, notice: 'Garden was successfully created.' }
|
||||
format.json { render json: @garden, status: :created, location: @garden }
|
||||
expire_fragment("homepage_stats")
|
||||
else
|
||||
format.html { render action: "new" }
|
||||
format.json { render json: @garden.errors, status: :unprocessable_entity }
|
||||
@@ -69,7 +69,7 @@ class GardensController < ApplicationController
|
||||
@garden = Garden.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
if @garden.update_attributes(params[:garden])
|
||||
if @garden.update(garden_params)
|
||||
format.html { redirect_to @garden, notice: 'Garden was successfully updated.' }
|
||||
format.json { head :no_content }
|
||||
else
|
||||
@@ -84,10 +84,18 @@ class GardensController < ApplicationController
|
||||
def destroy
|
||||
@garden = Garden.find(params[:id])
|
||||
@garden.destroy
|
||||
expire_fragment("homepage_stats")
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to gardens_by_owner_path(:owner => @garden.owner), notice: 'Garden was successfully deleted.' }
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def garden_params
|
||||
params.require(:garden).permit(:name, :slug, :owner_id, :description, :active,
|
||||
:location, :latitude, :longitude, :area, :area_unit)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,7 +20,7 @@ class HarvestsController < ApplicationController
|
||||
format.html { @harvests = @harvests.paginate(:page => params[:page]) }
|
||||
format.json { render json: @harvests }
|
||||
format.csv do
|
||||
specifics = (@owner ? "#{@owner.name}-" : @crop ? "#{@crop.name}-" : nil)
|
||||
specifics = (@owner ? "#{@owner.login_name}-" : @crop ? "#{@crop.name}-" : nil)
|
||||
@filename = "Growstuff-#{specifics}Harvests-#{Time.zone.now.to_s(:number)}.csv"
|
||||
render :csv => @harvests
|
||||
end
|
||||
@@ -62,7 +62,7 @@ class HarvestsController < ApplicationController
|
||||
def create
|
||||
params[:harvest][:owner_id] = current_member.id
|
||||
params[:harvested_at] = parse_date(params[:harvested_at])
|
||||
@harvest = Harvest.new(params[:harvest])
|
||||
@harvest = Harvest.new(harvest_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @harvest.save
|
||||
@@ -81,7 +81,7 @@ class HarvestsController < ApplicationController
|
||||
@harvest = Harvest.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
if @harvest.update_attributes(params[:harvest])
|
||||
if @harvest.update(harvest_params)
|
||||
format.html { redirect_to @harvest, notice: 'Harvest was successfully updated.' }
|
||||
format.json { head :no_content }
|
||||
else
|
||||
@@ -102,4 +102,11 @@ class HarvestsController < ApplicationController
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def harvest_params
|
||||
params.require(:harvest).permit(:crop_id, :harvested_at, :description, :owner_id,
|
||||
:quantity, :unit, :weight_quantity, :weight_unit, :plant_part_id, :slug, :si_weight)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
class MembersController < ApplicationController
|
||||
load_and_authorize_resource
|
||||
|
||||
cache_sweeper :member_sweeper
|
||||
|
||||
skip_authorize_resource :only => :nearby
|
||||
|
||||
after_action :expire_cache_fragments, :only => :create
|
||||
|
||||
def index
|
||||
@members = Member.confirmed.paginate(:page => params[:page])
|
||||
@sort = params[:sort]
|
||||
if @sort == 'recently_joined'
|
||||
@members = Member.confirmed.recently_joined.paginate(:page => params[:page])
|
||||
else
|
||||
@members = Member.confirmed.paginate(:page => params[:page])
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.html # index.html.haml
|
||||
@@ -44,4 +49,10 @@ class MembersController < ApplicationController
|
||||
@followers = @member.followers.paginate(:page => params[:page])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def expire_cache_fragments
|
||||
expire_fragment("homepage_stats")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -5,7 +5,7 @@ class NotificationsController < ApplicationController
|
||||
|
||||
# GET /notifications
|
||||
def index
|
||||
@notifications = Notification.find_all_by_recipient_id(current_member)
|
||||
@notifications = Notification.where(recipient_id: current_member)
|
||||
|
||||
respond_to do |format|
|
||||
format.html # index.html.erb
|
||||
@@ -49,7 +49,7 @@ class NotificationsController < ApplicationController
|
||||
# POST /notifications
|
||||
def create
|
||||
params[:notification][:sender_id] = current_member.id
|
||||
@notification = Notification.new(params[:notification])
|
||||
@notification = Notification.new(notification_params)
|
||||
@recipient = Member.find_by_id(params[:notification][:recipient_id])
|
||||
|
||||
respond_to do |format|
|
||||
@@ -60,4 +60,10 @@ class NotificationsController < ApplicationController
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def notification_params
|
||||
params.require(:notification).permit(:sender_id, :recipient_id, :subject, :body, :post_id, :read)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,7 +7,7 @@ class OrderItemsController < ApplicationController
|
||||
if params[:order_item][:price]
|
||||
params[:order_item][:price] = params[:order_item][:price].to_f * 100 # convert to cents
|
||||
end
|
||||
@order_item = OrderItem.new(params[:order_item])
|
||||
@order_item = OrderItem.new(order_item_params)
|
||||
@order_item.order = current_member.current_order || Order.create(:member_id => current_member.id)
|
||||
|
||||
respond_to do |format|
|
||||
@@ -20,4 +20,10 @@ class OrderItemsController < ApplicationController
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def order_item_params
|
||||
params.require(:order_item).permit(:order_id, :price, :product_id, :quantity)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ class OrdersController < ApplicationController
|
||||
|
||||
# GET /orders
|
||||
def index
|
||||
@orders = Order.find_all_by_member_id(current_member.id)
|
||||
@orders = Order.where(member_id: current_member.id)
|
||||
|
||||
respond_to do |format|
|
||||
format.html # index.html.erb
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
class PhotosController < ApplicationController
|
||||
before_filter :authenticate_member!, :except => [:index, :show]
|
||||
load_and_authorize_resource
|
||||
|
||||
cache_sweeper :photo_sweeper
|
||||
|
||||
# GET /photos
|
||||
# GET /photos.json
|
||||
@@ -61,13 +59,13 @@ class PhotosController < ApplicationController
|
||||
# POST /photos.json
|
||||
def create
|
||||
@photo = Photo.find_by_flickr_photo_id(params[:photo][:flickr_photo_id]) ||
|
||||
Photo.new(params[:photo])
|
||||
Photo.new(photo_params)
|
||||
@photo.owner_id = current_member.id
|
||||
@photo.set_flickr_metadata
|
||||
|
||||
# several models can have photos. we need to know what model and the id
|
||||
# for the entry to attach the photo to
|
||||
valid_models = ["planting", "harvest"]
|
||||
valid_models = ["planting", "harvest", "garden"]
|
||||
if params[:type]
|
||||
if valid_models.include?(params[:type])
|
||||
if params[:id]
|
||||
@@ -111,7 +109,7 @@ class PhotosController < ApplicationController
|
||||
@photo = Photo.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
if @photo.update_attributes(params[:photo])
|
||||
if @photo.update(photo_params)
|
||||
format.html { redirect_to @photo, notice: 'Photo was successfully updated.' }
|
||||
format.json { head :no_content }
|
||||
else
|
||||
@@ -132,4 +130,11 @@ class PhotosController < ApplicationController
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def photo_params
|
||||
params.require(:photo).permit(:flickr_photo_id, :owner_id, :title, :license_name,
|
||||
:license_url, :thumbnail_url, :fullsize_url, :link_url)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -42,7 +42,7 @@ class PlantPartsController < ApplicationController
|
||||
# POST /plant_parts
|
||||
# POST /plant_parts.json
|
||||
def create
|
||||
@plant_part = PlantPart.new(params[:plant_part])
|
||||
@plant_part = PlantPart.new(plant_part_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @plant_part.save
|
||||
@@ -61,7 +61,7 @@ class PlantPartsController < ApplicationController
|
||||
@plant_part = PlantPart.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
if @plant_part.update_attributes(params[:plant_part])
|
||||
if @plant_part.update(plant_part_params)
|
||||
format.html { redirect_to @plant_part, notice: 'Plant part was successfully updated.' }
|
||||
format.json { head :no_content }
|
||||
else
|
||||
@@ -82,4 +82,10 @@ class PlantPartsController < ApplicationController
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def plant_part_params
|
||||
params.require(:plant_part).permit(:name, :slug)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
class PlantingsController < ApplicationController
|
||||
before_filter :authenticate_member!, :except => [:index, :show]
|
||||
load_and_authorize_resource
|
||||
|
||||
|
||||
cache_sweeper :planting_sweeper
|
||||
|
||||
# GET /plantings
|
||||
# GET /plantings.json
|
||||
@@ -33,7 +30,7 @@ class PlantingsController < ApplicationController
|
||||
# GET /plantings/1
|
||||
# GET /plantings/1.json
|
||||
def show
|
||||
@planting = Planting.includes(:owner, :crop, :garden, :photos).find(params[:id])
|
||||
@planting = Planting.includes(:owner, :crop, :garden, :photos).friendly.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
format.html # show.html.erb
|
||||
@@ -68,14 +65,15 @@ class PlantingsController < ApplicationController
|
||||
# POST /plantings
|
||||
# POST /plantings.json
|
||||
def create
|
||||
params[:planting][:owner_id] = current_member.id
|
||||
params[:planted_at] = parse_date(params[:planted_at])
|
||||
@planting = Planting.new(params[:planting])
|
||||
@planting = Planting.new(planting_params)
|
||||
@planting.owner = current_member
|
||||
|
||||
respond_to do |format|
|
||||
if @planting.save
|
||||
format.html { redirect_to @planting, notice: 'Planting was successfully created.' }
|
||||
format.json { render json: @planting, status: :created, location: @planting }
|
||||
expire_fragment("homepage_stats")
|
||||
else
|
||||
format.html { render action: "new" }
|
||||
format.json { render json: @planting.errors, status: :unprocessable_entity }
|
||||
@@ -90,7 +88,7 @@ class PlantingsController < ApplicationController
|
||||
params[:planted_at] = parse_date(params[:planted_at])
|
||||
|
||||
respond_to do |format|
|
||||
if @planting.update_attributes(params[:planting])
|
||||
if @planting.update(planting_params)
|
||||
format.html { redirect_to @planting, notice: 'Planting was successfully updated.' }
|
||||
format.json { head :no_content }
|
||||
else
|
||||
@@ -106,10 +104,19 @@ class PlantingsController < ApplicationController
|
||||
@planting = Planting.find(params[:id])
|
||||
@garden = @planting.garden
|
||||
@planting.destroy
|
||||
expire_fragment("homepage_stats")
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to @garden }
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def planting_params
|
||||
params.require(:planting).permit(:crop_id, :description, :garden_id, :planted_at,
|
||||
:quantity, :sunniness, :planted_from, :owner_id, :finished,
|
||||
:finished_at)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,8 +2,6 @@ class PostsController < ApplicationController
|
||||
before_filter :authenticate_member!, :except => [:index, :show]
|
||||
load_and_authorize_resource
|
||||
|
||||
cache_sweeper :post_sweeper
|
||||
|
||||
# GET /posts
|
||||
# GET /posts.json
|
||||
|
||||
@@ -58,7 +56,7 @@ class PostsController < ApplicationController
|
||||
# POST /posts.json
|
||||
def create
|
||||
params[:post][:author_id] = current_member.id
|
||||
@post = Post.new(params[:post])
|
||||
@post = Post.new(post_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @post.save
|
||||
@@ -77,7 +75,7 @@ class PostsController < ApplicationController
|
||||
@post = Post.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
if @post.update_attributes(params[:post])
|
||||
if @post.update(post_params)
|
||||
format.html { redirect_to @post, notice: 'Post was successfully updated.' }
|
||||
format.json { head :no_content }
|
||||
else
|
||||
@@ -98,4 +96,10 @@ class PostsController < ApplicationController
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def post_params
|
||||
params.require(:post).permit(:body, :subject, :author_id, :forum_id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,7 +36,7 @@ class ProductsController < ApplicationController
|
||||
|
||||
# POST /products
|
||||
def create
|
||||
@product = Product.new(params[:product])
|
||||
@product = Product.new(product_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @product.save
|
||||
@@ -52,7 +52,7 @@ class ProductsController < ApplicationController
|
||||
@product = Product.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
if @product.update_attributes(params[:product])
|
||||
if @product.update(product_params)
|
||||
format.html { redirect_to @product, notice: 'Product was successfully updated.' }
|
||||
else
|
||||
format.html { render action: "edit" }
|
||||
@@ -69,4 +69,11 @@ class ProductsController < ApplicationController
|
||||
format.html { redirect_to products_url }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def product_params
|
||||
params.require(:product).permit(:description, :min_price, :recommended_price, :name,
|
||||
:account_type_id, :paid_months)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
class RegistrationsController < Devise::RegistrationsController
|
||||
|
||||
cache_sweeper :member_sweeper
|
||||
|
||||
def edit
|
||||
@twitter_auth = current_member.auth('twitter')
|
||||
@flickr_auth = current_member.auth('flickr')
|
||||
|
||||
@@ -36,7 +36,7 @@ class RolesController < ApplicationController
|
||||
|
||||
# POST /roles
|
||||
def create
|
||||
@role = Role.new(params[:role])
|
||||
@role = Role.new(role_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @role.save
|
||||
@@ -52,7 +52,7 @@ class RolesController < ApplicationController
|
||||
@role = Role.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
if @role.update_attributes(params[:role])
|
||||
if @role.update(role_params)
|
||||
format.html { redirect_to @role, notice: 'Role was successfully updated.' }
|
||||
else
|
||||
format.html { render action: "edit" }
|
||||
@@ -69,4 +69,10 @@ class RolesController < ApplicationController
|
||||
format.html { redirect_to roles_url }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def role_params
|
||||
params.require(:role).permit(:description, :name, :members, :slug)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,8 +2,6 @@ class ScientificNamesController < ApplicationController
|
||||
before_filter :authenticate_member!, :except => [:index, :show]
|
||||
load_and_authorize_resource
|
||||
|
||||
cache_sweeper :scientific_name_sweeper
|
||||
|
||||
# GET /scientific_names
|
||||
# GET /scientific_names.json
|
||||
def index
|
||||
@@ -47,7 +45,7 @@ class ScientificNamesController < ApplicationController
|
||||
# POST /scientific_names.json
|
||||
def create
|
||||
params[:scientific_name][:creator_id] = current_member.id
|
||||
@scientific_name = ScientificName.new(params[:scientific_name])
|
||||
@scientific_name = ScientificName.new(scientific_name_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @scientific_name.save
|
||||
@@ -66,7 +64,7 @@ class ScientificNamesController < ApplicationController
|
||||
@scientific_name = ScientificName.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
if @scientific_name.update_attributes(params[:scientific_name])
|
||||
if @scientific_name.update(scientific_name_params)
|
||||
format.html { redirect_to @scientific_name.crop, notice: 'Scientific name was successfully updated.' }
|
||||
format.json { head :no_content }
|
||||
else
|
||||
@@ -90,4 +88,10 @@ class ScientificNamesController < ApplicationController
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def scientific_name_params
|
||||
params.require(:scientific_name).permit(:crop_id, :scientific_name, :creator_id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,8 +2,6 @@ class SeedsController < ApplicationController
|
||||
before_filter :authenticate_member!, :except => [:index, :show]
|
||||
load_and_authorize_resource
|
||||
|
||||
cache_sweeper :seed_sweeper
|
||||
|
||||
# GET /seeds
|
||||
# GET /seeds.json
|
||||
def index
|
||||
@@ -68,7 +66,7 @@ class SeedsController < ApplicationController
|
||||
# POST /seeds.json
|
||||
def create
|
||||
params[:seed][:owner_id] = current_member.id
|
||||
@seed = Seed.new(params[:seed])
|
||||
@seed = Seed.new(seed_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @seed.save
|
||||
@@ -87,7 +85,7 @@ class SeedsController < ApplicationController
|
||||
@seed = Seed.find(params[:id])
|
||||
|
||||
respond_to do |format|
|
||||
if @seed.update_attributes(params[:seed])
|
||||
if @seed.update(seed_params)
|
||||
format.html { redirect_to @seed, notice: 'Seed was successfully updated.' }
|
||||
format.json { head :no_content }
|
||||
else
|
||||
@@ -108,4 +106,13 @@ class SeedsController < ApplicationController
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def seed_params
|
||||
params.require(:seed).permit(
|
||||
:owner_id, :crop_id, :description, :quantity, :plant_before,
|
||||
:days_until_maturity_min, :days_until_maturity_max, :organic, :gmo,
|
||||
:heirloom, :tradable_to, :slug)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -24,5 +24,12 @@ module ApplicationHelper
|
||||
:target => "_blank"
|
||||
end
|
||||
|
||||
# Produces a cache key for uniquely identifying cached fragments.
|
||||
def cache_key_for(klass, identifier="all")
|
||||
count = klass.count
|
||||
max_updated_at = klass.maximum(:updated_at).try(:utc).try(:to_s, :number)
|
||||
"#{klass.name.downcase.pluralize}/#{identifier}-#{count}-#{max_updated_at}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ class Notifier < ActionMailer::Base
|
||||
def planting_reminder(member)
|
||||
@member = member
|
||||
|
||||
@plantings = @member.plantings.reorder.last(5)
|
||||
@harvests = @member.harvests.reorder.last(5)
|
||||
@plantings = @member.plantings.first(5)
|
||||
@harvests = @member.harvests.first(5)
|
||||
|
||||
if @member.send_planting_reminder
|
||||
mail(:to => @member.email,
|
||||
@@ -22,4 +22,19 @@ class Notifier < ActionMailer::Base
|
||||
end
|
||||
end
|
||||
|
||||
def new_crop_request(member, request)
|
||||
@member, @request = member, 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
|
||||
mail(:to => @member.email, :subject => "#{crop.name.capitalize} has been approved")
|
||||
end
|
||||
|
||||
def crop_request_rejected(member, crop)
|
||||
@member, @crop = member, crop
|
||||
mail(:to => @member.email, :subject => "#{crop.name.capitalize} has been rejected")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -21,7 +21,24 @@ class Ability
|
||||
cannot :read, Account
|
||||
cannot :read, AccountType
|
||||
|
||||
# nobody should be able to view unapproved crops unless they
|
||||
# are wranglers or admins
|
||||
cannot :read, Crop
|
||||
can :read, Crop, :approval_status => "approved"
|
||||
# scientific names should only be viewable if associated crop is approved
|
||||
cannot :read, ScientificName
|
||||
can :read, ScientificName do |sn|
|
||||
sn.crop.approved?
|
||||
end
|
||||
# ... same for alternate names
|
||||
cannot :read, AlternateName
|
||||
can :read, AlternateName do |an|
|
||||
an.crop.approved?
|
||||
end
|
||||
|
||||
if member
|
||||
# members can see even rejected or pending crops if they requested it
|
||||
can :read, Crop, :requester_id => member.id
|
||||
|
||||
# managing your own user settings
|
||||
can :update, Member, :id => member.id
|
||||
@@ -45,6 +62,9 @@ class Ability
|
||||
can :manage, AlternateName
|
||||
end
|
||||
|
||||
# any member can create a crop provisionally
|
||||
can :create, Crop
|
||||
|
||||
# can create & destroy their own authentications against other sites.
|
||||
can :create, Authentication
|
||||
can :destroy, Authentication, :member_id => member.id
|
||||
@@ -94,9 +114,11 @@ class Ability
|
||||
cannot :destroy, OrderItem, :order => { :member_id => member.id, :completed_at => nil }
|
||||
|
||||
# following/unfollowing permissions
|
||||
can :create, Follow do |f|
|
||||
!member.already_following?(f.followed) && f.followed_id != member.id
|
||||
end
|
||||
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
|
||||
|
||||
if member.has_role? :admin
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class Account < ActiveRecord::Base
|
||||
attr_accessible :account_type_id, :member_id, :paid_until
|
||||
belongs_to :member
|
||||
belongs_to :account_type
|
||||
|
||||
@@ -9,7 +8,7 @@ class Account < ActiveRecord::Base
|
||||
|
||||
before_create do |account|
|
||||
unless account.account_type
|
||||
account.account_type = AccountType.find_or_create_by_name(
|
||||
account.account_type = AccountType.find_or_create_by(name:
|
||||
Growstuff::Application.config.default_account_type
|
||||
)
|
||||
end
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class AccountType < ActiveRecord::Base
|
||||
attr_accessible :is_paid, :is_permanent_paid, :name
|
||||
has_many :products
|
||||
|
||||
def to_s
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class AlternateName < ActiveRecord::Base
|
||||
attr_accessible :crop_id, :name, :creator_id
|
||||
after_commit { |an| an.crop.__elasticsearch__.index_document if an.crop }
|
||||
belongs_to :crop
|
||||
belongs_to :creator, :class_name => 'Member'
|
||||
end
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
class Authentication < ActiveRecord::Base
|
||||
belongs_to :member
|
||||
attr_accessible :provider, :uid, :token, :secret, :name
|
||||
end
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
class Comment < ActiveRecord::Base
|
||||
attr_accessible :author_id, :body, :post_id
|
||||
belongs_to :author, :class_name => 'Member'
|
||||
belongs_to :post
|
||||
|
||||
default_scope order("created_at DESC")
|
||||
scope :post_order, reorder("created_at ASC") # for display on post page
|
||||
default_scope { order("created_at DESC") }
|
||||
scope :post_order, -> { reorder("created_at ASC") } # for display on post page
|
||||
|
||||
after_create do
|
||||
recipient = self.post.author.id
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
class CommentSweeper < ActionController::Caching::Sweeper
|
||||
observe Comment
|
||||
|
||||
def after_create(comment)
|
||||
expire_fragment('recent_posts')
|
||||
end
|
||||
|
||||
def after_update(comment)
|
||||
end
|
||||
|
||||
def after_destroy(comment)
|
||||
expire_fragment('recent_posts')
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,38 +1,113 @@
|
||||
class Crop < ActiveRecord::Base
|
||||
extend FriendlyId
|
||||
friendly_id :name, use: :slugged
|
||||
attr_accessible :en_wikipedia_url, :name, :parent_id, :creator_id, :scientific_names_attributes
|
||||
friendly_id :name, use: [:slugged, :finders]
|
||||
|
||||
has_many :scientific_names
|
||||
has_many :scientific_names, after_add: :update_index, after_remove: :update_index
|
||||
accepts_nested_attributes_for :scientific_names,
|
||||
:allow_destroy => true,
|
||||
:reject_if => :all_blank
|
||||
|
||||
has_many :alternate_names
|
||||
has_many :alternate_names, after_add: :update_index, after_remove: :update_index
|
||||
has_many :plantings
|
||||
has_many :photos, :through => :plantings
|
||||
has_many :seeds
|
||||
has_many :harvests
|
||||
has_many :plant_parts, :through => :harvests, :uniq => :true
|
||||
has_many :plant_parts, -> { uniq }, :through => :harvests
|
||||
belongs_to :creator, :class_name => 'Member'
|
||||
belongs_to :requester, :class_name => 'Member'
|
||||
|
||||
belongs_to :parent, :class_name => 'Crop'
|
||||
has_many :varieties, :class_name => 'Crop', :foreign_key => 'parent_id'
|
||||
has_and_belongs_to_many :posts
|
||||
before_destroy {|crop| crop.posts.clear}
|
||||
|
||||
default_scope { order("lower(name) asc") }
|
||||
scope :recent, -> { where(:approval_status => "approved").reorder("created_at desc") }
|
||||
scope :toplevel, -> { where(:approval_status => "approved", :parent_id => nil) }
|
||||
scope :popular, -> { where(:approval_status => "approved").reorder("plantings_count desc, lower(name) asc") }
|
||||
scope :randomized, -> { where(:approval_status => "approved").reorder('random()') } # ok on sqlite and psql, but not on mysql
|
||||
scope :pending_approval, -> { where(:approval_status => "pending") }
|
||||
scope :rejected, -> { where(:approval_status => "rejected") }
|
||||
|
||||
default_scope order("lower(name) asc")
|
||||
scope :recent, reorder("created_at desc")
|
||||
scope :toplevel, where(:parent_id => nil)
|
||||
scope :popular, reorder("plantings_count desc, lower(name) asc")
|
||||
scope :randomized, reorder('random()') # ok on sqlite and psql, but not on mysql
|
||||
|
||||
## Wikipedia urls are only necessary when approving a crop
|
||||
validates :en_wikipedia_url,
|
||||
:format => {
|
||||
:with => /^https?:\/\/en\.wikipedia\.org\/wiki/,
|
||||
:with => /\Ahttps?:\/\/en\.wikipedia\.org\/wiki/,
|
||||
:message => 'is not a valid English Wikipedia URL'
|
||||
}
|
||||
},
|
||||
:if => :approved?
|
||||
|
||||
## Reasons are only necessary when rejecting
|
||||
validates :reason_for_rejection, :presence => true, :if => :rejected?
|
||||
|
||||
## This validation addresses a race condition
|
||||
validate :approval_status_cannot_be_changed_again
|
||||
|
||||
validate :must_be_rejected_if_rejected_reasons_present
|
||||
|
||||
validate :must_have_meaningful_reason_for_rejection
|
||||
|
||||
####################################
|
||||
# Elastic search configuration
|
||||
include Elasticsearch::Model
|
||||
include Elasticsearch::Model::Callbacks
|
||||
# In order to avoid clashing between different environments,
|
||||
# use Rails.env as a part of index name (eg. development_growstuff)
|
||||
index_name [Rails.env, "growstuff"].join('_')
|
||||
settings index: { number_of_shards: 1 },
|
||||
analysis: {
|
||||
tokenizer: {
|
||||
gs_edgeNGram_tokenizer: {
|
||||
type: "edgeNGram", # edgeNGram: NGram match from the start of a token
|
||||
min_gram: 3,
|
||||
max_gram: 10,
|
||||
# token_chars: Elasticsearch will split on characters
|
||||
# that don’t belong to any of these classes
|
||||
token_chars: [ "letter", "digit" ]
|
||||
}
|
||||
},
|
||||
analyzer: {
|
||||
gs_edgeNGram_analyzer: {
|
||||
tokenizer: "gs_edgeNGram_tokenizer",
|
||||
filter: ["lowercase"]
|
||||
}
|
||||
},
|
||||
} do
|
||||
mappings dynamic: 'false' do
|
||||
indexes :id, type: 'long'
|
||||
indexes :name, type: 'string', analyzer: 'gs_edgeNGram_analyzer'
|
||||
indexes :scientific_names do
|
||||
indexes :scientific_name,
|
||||
type: 'string',
|
||||
analyzer: 'gs_edgeNGram_analyzer',
|
||||
# Disabling field-length norm (norm). If the norm option is turned on(by default),
|
||||
# higher weigh would be given for shorter fields, which in our case is irrelevant.
|
||||
norms: { enabled: false }
|
||||
end
|
||||
indexes :alternate_names do
|
||||
indexes :name, type: 'string', analyzer: 'gs_edgeNGram_analyzer'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def as_indexed_json(options={})
|
||||
self.as_json(
|
||||
only: [:id, :name],
|
||||
include: {
|
||||
scientific_names: { only: :scientific_name },
|
||||
alternate_names: { only: :name }
|
||||
})
|
||||
end
|
||||
|
||||
# update the Elasticsearch index (only if we're using it in this
|
||||
# environment)
|
||||
def update_index(name_obj)
|
||||
if ENV["GROWSTUFF_ELASTICSEARCH"] == "true"
|
||||
__elasticsearch__.index_document
|
||||
end
|
||||
end
|
||||
|
||||
# End Elasticsearch section
|
||||
|
||||
def to_s
|
||||
return name
|
||||
@@ -105,6 +180,26 @@ class Crop < ActiveRecord::Base
|
||||
return true
|
||||
end
|
||||
|
||||
def pending?
|
||||
approval_status == "pending"
|
||||
end
|
||||
|
||||
def approved?
|
||||
approval_status == "approved"
|
||||
end
|
||||
|
||||
def rejected?
|
||||
approval_status == "rejected"
|
||||
end
|
||||
|
||||
def approval_statuses
|
||||
[ 'rejected', 'pending', 'approved' ]
|
||||
end
|
||||
|
||||
def reasons_for_rejection
|
||||
[ "already in database", "not edible", "not enough information", "other" ]
|
||||
end
|
||||
|
||||
# Crop.interesting
|
||||
# returns a list of interesting crops, for use on the homepage etc
|
||||
def Crop.interesting
|
||||
@@ -132,7 +227,7 @@ class Crop < ActiveRecord::Base
|
||||
cropbot = Member.find_by_login_name('cropbot')
|
||||
raise "cropbot account not found: run rake db:seed" unless cropbot
|
||||
|
||||
crop = Crop.find_or_create_by_name(name)
|
||||
crop = Crop.find_or_create_by(name: name)
|
||||
crop.update_attributes(
|
||||
:en_wikipedia_url => en_wikipedia_url,
|
||||
:creator_id => cropbot.id
|
||||
@@ -203,10 +298,48 @@ class Crop < ActiveRecord::Base
|
||||
end
|
||||
|
||||
# Crop.search(string)
|
||||
# searches for crops whose names match the string given
|
||||
# just uses SQL LIKE for now, but can be made fancier later
|
||||
def self.search(query)
|
||||
where("name ILIKE ?", "%#{query}%")
|
||||
if ENV['GROWSTUFF_ELASTICSEARCH'] == "true"
|
||||
search_str = query.nil? ? "" : query.downcase
|
||||
response = __elasticsearch__.search( {
|
||||
# Finds documents which match any field, but uses the _score from
|
||||
# the best field insead of adding up _score from each field.
|
||||
query: {
|
||||
multi_match: {
|
||||
query: "#{search_str}",
|
||||
fields: ["name", "scientific_names.scientific_name", "alternate_names.name"]
|
||||
}
|
||||
},
|
||||
size: 50
|
||||
}
|
||||
)
|
||||
return response.records.to_a
|
||||
else
|
||||
where("name ILIKE ?", "%#{query}%").load
|
||||
end
|
||||
end
|
||||
|
||||
# Custom validations
|
||||
|
||||
def approval_status_cannot_be_changed_again
|
||||
previous = previous_changes.include?(:approval_status) ? previous_changes.approval_status : {}
|
||||
if previous.include?(:rejected) || previous.include?(:approved)
|
||||
errors.add(:approval_status, "has already been set to #{approval_status}")
|
||||
end
|
||||
end
|
||||
|
||||
def must_be_rejected_if_rejected_reasons_present
|
||||
unless rejected?
|
||||
if reason_for_rejection.present? || rejection_notes.present?
|
||||
errors.add(:approval_status, "must be rejected if a reason for rejection is present")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def must_have_meaningful_reason_for_rejection
|
||||
if reason_for_rejection == "other" && rejection_notes.blank?
|
||||
errors.add(:rejection_notes, "must be added if the reason for rejection is \"other\"")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
class CropSweeper < ActionController::Caching::Sweeper
|
||||
observe Crop
|
||||
|
||||
def after_create(crop)
|
||||
expire_fragment('homepage_stats')
|
||||
expire_fragment('recent_crops')
|
||||
expire_fragment('full_crop_hierarchy')
|
||||
end
|
||||
|
||||
def after_update(crop)
|
||||
expire_fragment("crop_image_#{crop.id}")
|
||||
end
|
||||
|
||||
def after_destroy(crop)
|
||||
expire_fragment('homepage_stats')
|
||||
expire_fragment('recent_crops')
|
||||
expire_fragment('full_crop_hierarchy')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class Follow < ActiveRecord::Base
|
||||
attr_accessible :followed_id, :follower_id
|
||||
belongs_to :follower, class_name: "Member"
|
||||
belongs_to :followed, class_name: "Member"
|
||||
validates :follower_id, uniqueness: { :scope => :followed_id }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class Forum < ActiveRecord::Base
|
||||
extend FriendlyId
|
||||
friendly_id :name, use: :slugged
|
||||
attr_accessible :description, :name, :owner_id, :slug
|
||||
friendly_id :name, use: [:slugged, :finders]
|
||||
|
||||
has_many :posts
|
||||
belongs_to :owner, :class_name => "Member"
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
class ForumSweeper < ActionController::Caching::Sweeper
|
||||
observe Forum
|
||||
|
||||
def after_create(forum)
|
||||
expire_fragment('homepage_forums')
|
||||
end
|
||||
|
||||
def after_update(forum)
|
||||
expire_fragment('homepage_forums')
|
||||
end
|
||||
|
||||
def after_destroy(forum)
|
||||
expire_fragment('homepage_forums')
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,24 +1,32 @@
|
||||
class Garden < ActiveRecord::Base
|
||||
include Geocodable
|
||||
extend FriendlyId
|
||||
friendly_id :garden_slug, use: :slugged
|
||||
|
||||
attr_accessible :name, :slug, :owner_id, :description, :active,
|
||||
:location, :latitude, :longitude, :area, :area_unit
|
||||
friendly_id :garden_slug, use: [:slugged, :finders]
|
||||
|
||||
belongs_to :owner, :class_name => 'Member', :foreign_key => 'owner_id'
|
||||
has_many :plantings, :order => 'created_at DESC', :dependent => :destroy
|
||||
has_many :plantings, -> { order(created_at: :desc) }, :dependent => :destroy
|
||||
has_many :crops, :through => :plantings
|
||||
|
||||
has_and_belongs_to_many :photos
|
||||
|
||||
before_destroy do |garden|
|
||||
photolist = garden.photos.to_a # save a temp copy of the photo list
|
||||
garden.photos.clear # clear relationship b/w garden and photo
|
||||
|
||||
photolist.each do |photo|
|
||||
photo.destroy_if_unused
|
||||
end
|
||||
end
|
||||
|
||||
# set up geocoding
|
||||
geocoded_by :location
|
||||
after_validation :geocode
|
||||
after_validation :empty_unwanted_geocodes
|
||||
after_save :mark_inactive_garden_plantings_as_finished
|
||||
|
||||
default_scope order("lower(name) asc")
|
||||
scope :active, where(:active => true)
|
||||
scope :inactive, where(:active => false)
|
||||
default_scope { order("lower(name) asc") }
|
||||
scope :active, -> { where(:active => true) }
|
||||
scope :inactive, -> { where(:active => false) }
|
||||
|
||||
validates :name,
|
||||
:format => {
|
||||
@@ -26,7 +34,9 @@ class Garden < ActiveRecord::Base
|
||||
}
|
||||
|
||||
validates :area,
|
||||
:numericality => { :only_integer => false, :greater_than_or_equal_to => 0 },
|
||||
:numericality => {
|
||||
:only_integer => false,
|
||||
:greater_than_or_equal_to => 0 },
|
||||
:allow_nil => true
|
||||
|
||||
AREA_UNITS_VALUES = {
|
||||
@@ -86,4 +96,8 @@ class Garden < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def default_photo
|
||||
return photos.first
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
class GardenSweeper < ActionController::Caching::Sweeper
|
||||
observe Garden
|
||||
|
||||
def after_create(garden)
|
||||
expire_fragment('homepage_stats')
|
||||
expire_fragment('interesting_members') if garden.owner.interesting?
|
||||
expire_fragment("member_thumbnail_#{garden.owner.id}")
|
||||
end
|
||||
|
||||
def after_destroy(garden)
|
||||
expire_fragment('homepage_stats')
|
||||
expire_fragment('interesting_members') if garden.owner.interesting?
|
||||
expire_fragment("member_thumbnail_#{garden.owner.id}")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
class Harvest < ActiveRecord::Base
|
||||
include ActionView::Helpers::NumberHelper
|
||||
extend FriendlyId
|
||||
friendly_id :harvest_slug, use: :slugged
|
||||
|
||||
attr_accessible :crop_id, :harvested_at, :description, :owner_id,
|
||||
:quantity, :unit, :weight_quantity, :weight_unit, :plant_part_id, :slug
|
||||
friendly_id :harvest_slug, use: [:slugged, :finders]
|
||||
|
||||
belongs_to :crop
|
||||
belongs_to :owner, :class_name => 'Member'
|
||||
@@ -21,12 +18,16 @@ class Harvest < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
default_scope order('created_at DESC')
|
||||
default_scope { order('created_at DESC') }
|
||||
|
||||
validates :crop, :approved => true
|
||||
|
||||
validates :crop, :presence => {:message => "must be present and exist in our database"}
|
||||
|
||||
validates :quantity,
|
||||
:numericality => { :only_integer => false },
|
||||
:numericality => {
|
||||
:only_integer => false,
|
||||
:greater_than_or_equal_to => 0 },
|
||||
:allow_nil => true
|
||||
|
||||
UNITS_VALUES = {
|
||||
@@ -62,6 +63,17 @@ class Harvest < ActiveRecord::Base
|
||||
|
||||
after_validation :cleanup_quantities
|
||||
|
||||
before_save :set_si_weight
|
||||
|
||||
# we're storing the harvest weight in kilograms in the db too
|
||||
# to make data manipulation easier
|
||||
def set_si_weight
|
||||
if self.weight_unit != nil
|
||||
weight_string = "#{self.weight_quantity} #{self.weight_unit}"
|
||||
self.si_weight = Unit(weight_string).convert_to("kg").to_s("%0.3f").delete(" kg").to_f
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup_quantities
|
||||
if quantity == 0
|
||||
self.quantity = nil
|
||||
|
||||
@@ -2,7 +2,7 @@ class Member < ActiveRecord::Base
|
||||
include Geocodable
|
||||
extend FriendlyId
|
||||
|
||||
friendly_id :login_name, use: :slugged
|
||||
friendly_id :login_name, use: [:slugged, :finders]
|
||||
|
||||
has_many :posts, :foreign_key => 'author_id'
|
||||
has_many :comments, :foreign_key => 'author_id'
|
||||
@@ -27,18 +27,20 @@ class Member < ActiveRecord::Base
|
||||
|
||||
has_many :photos
|
||||
|
||||
|
||||
default_scope { order("lower(login_name) asc") }
|
||||
scope :confirmed, -> { where('confirmed_at IS NOT NULL') }
|
||||
scope :located, -> { where("location <> '' and latitude IS NOT NULL and longitude IS NOT NULL") }
|
||||
scope :recently_signed_in, -> { reorder('updated_at DESC') }
|
||||
scope :recently_joined, -> { reorder("confirmed_at desc") }
|
||||
scope :wants_newsletter, -> { where(:newsletter => true) }
|
||||
|
||||
has_many :follows, :class_name => "Follow", :foreign_key => "follower_id"
|
||||
has_many :followed, :through => :follows
|
||||
|
||||
has_many :inverse_follows, :class_name => "Follow", :foreign_key => "followed_id"
|
||||
has_many :followers, :through => :inverse_follows, :source => :follower
|
||||
|
||||
default_scope order("lower(login_name) asc")
|
||||
scope :confirmed, where('confirmed_at IS NOT NULL')
|
||||
scope :located, where("location <> '' and latitude IS NOT NULL and longitude IS NOT NULL")
|
||||
scope :recently_signed_in, reorder('updated_at DESC')
|
||||
scope :wants_newsletter, where(:newsletter => true)
|
||||
|
||||
# Include default devise modules. Others available are:
|
||||
# :token_authenticatable, :confirmable,
|
||||
# :lockable, :timeoutable and :omniauthable
|
||||
@@ -46,16 +48,6 @@ class Member < ActiveRecord::Base
|
||||
:recoverable, :rememberable, :trackable, :validatable,
|
||||
:confirmable, :lockable, :timeoutable
|
||||
|
||||
# Setup accessible (or protected) attributes for your model
|
||||
attr_accessible :login_name, :email, :password, :password_confirmation,
|
||||
:remember_me, :login,
|
||||
# terms of service
|
||||
:tos_agreement,
|
||||
# profile stuff
|
||||
:bio, :location, :latitude, :longitude,
|
||||
# email settings
|
||||
:show_email, :newsletter, :send_notification_email, :send_planting_reminder
|
||||
|
||||
# set up geocoding
|
||||
geocoded_by :location
|
||||
after_validation :geocode
|
||||
@@ -80,7 +72,7 @@ class Member < ActiveRecord::Base
|
||||
:message => "name is reserved"
|
||||
},
|
||||
:format => {
|
||||
:with => /^\w+$/,
|
||||
:with => /\A\w+\z/,
|
||||
:message => "may only include letters, numbers, or underscores"
|
||||
},
|
||||
:uniqueness => {
|
||||
@@ -93,7 +85,7 @@ class Member < ActiveRecord::Base
|
||||
# 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 FactoryGirl associations
|
||||
after_create {|member| Account.find_or_create_by_member_id(:member_id => member.id) }
|
||||
after_create {|member| Account.find_or_create_by(:member_id => member.id) }
|
||||
|
||||
after_save :update_newsletter_subscription
|
||||
|
||||
@@ -243,17 +235,19 @@ class Member < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def newsletter_subscribe
|
||||
def newsletter_subscribe(testing=false)
|
||||
return true if (Rails.env.test? && !testing)
|
||||
gb = Gibbon::API.new
|
||||
res = gb.lists.subscribe({
|
||||
:id => Gibbon::API.api_key,
|
||||
:email => { :email => email },
|
||||
:merge_vars => { :login_name => login_name },
|
||||
:double_optin => false # they alredy confirmed their email with us
|
||||
:double_optin => false # they already confirmed their email with us
|
||||
})
|
||||
end
|
||||
|
||||
def newsletter_unsubscribe
|
||||
def newsletter_unsubscribe(testing=false)
|
||||
return true if (Rails.env.test? && !testing)
|
||||
gb = Gibbon::API.new
|
||||
res = gb.lists.unsubscribe({
|
||||
:id => ENV['GROWSTUFF_MAILCHIMP_NEWSLETTER_ID'],
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
class MemberSweeper < ActionController::Caching::Sweeper
|
||||
observe Member
|
||||
|
||||
def after_create(member)
|
||||
expire_fragment('homepage_stats')
|
||||
end
|
||||
|
||||
def after_update(member)
|
||||
expire_fragment('interesting_members') if member.interesting?
|
||||
expire_fragment("interesting_seeds") if member.seeds.tradable.present?
|
||||
expire_fragment("member_thumbnail_#{member.id}")
|
||||
|
||||
if member.plantings.present?
|
||||
member.plantings.each do |p|
|
||||
expire_fragment("plantings_listitem_#{p.id}") if p.interesting?
|
||||
end
|
||||
expire_fragment('interesting_plantings')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
class Notification < ActiveRecord::Base
|
||||
attr_accessible :sender_id, :recipient_id,
|
||||
:subject, :body, :post_id, :read
|
||||
|
||||
belongs_to :sender, :class_name => 'Member'
|
||||
belongs_to :recipient, :class_name => 'Member'
|
||||
belongs_to :post
|
||||
|
||||
default_scope order('created_at DESC')
|
||||
scope :unread, where(:read => false)
|
||||
default_scope { order('created_at DESC') }
|
||||
scope :unread, -> { where(:read => false) }
|
||||
|
||||
before_create :replace_blank_subject
|
||||
after_create :send_email
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
class Order < ActiveRecord::Base
|
||||
attr_accessible :member_id, :completed_at, :referral_code
|
||||
belongs_to :member
|
||||
|
||||
has_many :order_items, :dependent => :destroy
|
||||
|
||||
default_scope order('created_at DESC')
|
||||
default_scope { order('created_at DESC') }
|
||||
|
||||
validates :referral_code, :format => {
|
||||
:with => /\A[a-zA-Z0-9 ]*\z/,
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
class OrderItem < ActiveRecord::Base
|
||||
attr_accessible :order_id, :price, :product_id, :quantity
|
||||
|
||||
belongs_to :order
|
||||
belongs_to :product
|
||||
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
class Photo < ActiveRecord::Base
|
||||
attr_accessible :flickr_photo_id, :owner_id, :title, :license_name,
|
||||
:license_url, :thumbnail_url, :fullsize_url, :link_url
|
||||
belongs_to :owner, :class_name => 'Member'
|
||||
|
||||
has_and_belongs_to_many :plantings
|
||||
has_and_belongs_to_many :harvests
|
||||
has_and_belongs_to_many :gardens
|
||||
before_destroy do |photo|
|
||||
photo.plantings.clear
|
||||
photo.harvests.clear
|
||||
photo.gardens.clear
|
||||
end
|
||||
|
||||
default_scope order("created_at desc")
|
||||
default_scope { order("created_at desc") }
|
||||
|
||||
# remove photos that aren't used by anything
|
||||
def destroy_if_unused
|
||||
unless plantings.size > 0 or harvests.size > 0
|
||||
unless plantings.size > 0 or harvests.size > 0 or gardens.size > 0
|
||||
self.destroy
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
class PhotoSweeper < ActionController::Caching::Sweeper
|
||||
observe Photo
|
||||
|
||||
def after_create(photo)
|
||||
expire_fragment('interesting_plantings')
|
||||
end
|
||||
|
||||
def after_destroy(photo)
|
||||
expire_fragment('interesting_plantings')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
class PlantPart < ActiveRecord::Base
|
||||
extend FriendlyId
|
||||
friendly_id :name, :use => :slugged
|
||||
friendly_id :name, :use => [:slugged, :finders]
|
||||
|
||||
has_many :harvests
|
||||
has_many :crops, :through => :harvests, :uniq => true
|
||||
|
||||
attr_accessible :name, :slug
|
||||
has_many :crops, -> { uniq }, :through => :harvests
|
||||
|
||||
def to_s
|
||||
return name
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
class Planting < ActiveRecord::Base
|
||||
extend FriendlyId
|
||||
friendly_id :planting_slug, use: :slugged
|
||||
|
||||
attr_accessible :crop_id, :description, :garden_id, :planted_at,
|
||||
:quantity, :sunniness, :planted_from, :owner_id, :finished,
|
||||
:finished_at
|
||||
friendly_id :planting_slug, use: [:slugged, :finders]
|
||||
|
||||
belongs_to :garden
|
||||
belongs_to :owner, :class_name => 'Member', :counter_cache => true
|
||||
@@ -21,9 +17,9 @@ class Planting < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
default_scope order("created_at desc")
|
||||
scope :finished, where(:finished => true)
|
||||
scope :current, where(:finished => false)
|
||||
default_scope { order("created_at desc") }
|
||||
scope :finished, -> { where(:finished => true) }
|
||||
scope :current, -> { where(:finished => false) }
|
||||
|
||||
delegate :name,
|
||||
:en_wikipedia_url,
|
||||
@@ -32,12 +28,16 @@ class Planting < ActiveRecord::Base
|
||||
:to => :crop,
|
||||
:prefix => true
|
||||
|
||||
default_scope order("created_at desc")
|
||||
default_scope { order("created_at desc") }
|
||||
|
||||
validates :crop_id, :presence => {:message => "must be present and exist in our database"}
|
||||
validates :crop, :approved => true
|
||||
|
||||
validates :crop, :presence => {:message => "must be present and exist in our database"}
|
||||
|
||||
validates :quantity,
|
||||
:numericality => { :only_integer => true },
|
||||
:numericality => {
|
||||
:only_integer => true,
|
||||
:greater_than_or_equal_to => 0 },
|
||||
:allow_nil => true
|
||||
|
||||
SUNNINESS_VALUES = %w(sun semi-shade shade)
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
class PlantingSweeper < ActionController::Caching::Sweeper
|
||||
observe Planting
|
||||
|
||||
def after_create(planting)
|
||||
expire_fragment('homepage_stats')
|
||||
expire_fragment("member_thumbnail_#{planting.owner.id}")
|
||||
expire_fragment("interesting_members") if planting.owner.interesting?
|
||||
expire_fragment("crop_image_#{planting.crop.id}")
|
||||
end
|
||||
|
||||
def after_update(planting)
|
||||
expire_fragment("planting_listitem_#{planting.id}")
|
||||
expire_fragment("planting_image_#{planting.id}")
|
||||
expire_fragment("interesting_plantings")
|
||||
end
|
||||
|
||||
def after_destroy(planting)
|
||||
expire_fragment('homepage_stats')
|
||||
expire_fragment("crop_image_#{planting.crop.id}")
|
||||
expire_fragment('interesting_plantings') if planting.interesting?
|
||||
expire_fragment("interesting_members") if planting.owner.interesting?
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
class Post < ActiveRecord::Base
|
||||
extend FriendlyId
|
||||
friendly_id :author_date_subject, use: :slugged
|
||||
attr_accessible :body, :subject, :author_id, :forum_id
|
||||
friendly_id :author_date_subject, use: [:slugged, :finders]
|
||||
belongs_to :author, :class_name => 'Member'
|
||||
belongs_to :forum
|
||||
has_many :comments, :dependent => :destroy
|
||||
@@ -11,7 +10,7 @@ class Post < ActiveRecord::Base
|
||||
# also has_many notifications, but kinda meaningless to get at them
|
||||
# from this direction, so we won't set up an association for now.
|
||||
|
||||
default_scope order("created_at desc")
|
||||
default_scope { order("created_at desc") }
|
||||
|
||||
validates :subject,
|
||||
:format => {
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
class PostSweeper < ActionController::Caching::Sweeper
|
||||
observe Post
|
||||
|
||||
def after_create(post)
|
||||
expire_fragment('recent_posts')
|
||||
end
|
||||
|
||||
def after_update(post)
|
||||
expire_fragment('recent_posts')
|
||||
end
|
||||
|
||||
def after_destroy(post)
|
||||
expire_fragment('recent_posts')
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,12 +1,12 @@
|
||||
class Product < ActiveRecord::Base
|
||||
attr_accessible :description, :min_price, :recommended_price, :name,
|
||||
:account_type_id, :paid_months
|
||||
|
||||
has_and_belongs_to_many :orders
|
||||
belongs_to :account_type
|
||||
|
||||
validates :paid_months, :numericality => { :only_integer => true,
|
||||
:allow_nil => true }
|
||||
validates :paid_months,
|
||||
:numericality => {
|
||||
:only_integer => true,
|
||||
:greater_than_or_equal_to => 0 },
|
||||
:allow_nil => true
|
||||
|
||||
def to_s
|
||||
name
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class Role < ActiveRecord::Base
|
||||
extend FriendlyId
|
||||
friendly_id :name, use: :slugged
|
||||
attr_accessible :description, :name, :members, :slug
|
||||
friendly_id :name, use: [:slugged, :finders]
|
||||
|
||||
has_and_belongs_to_many :members
|
||||
|
||||
class << self
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class ScientificName < ActiveRecord::Base
|
||||
attr_accessible :crop_id, :scientific_name, :creator_id
|
||||
after_commit { |sn| sn.crop.__elasticsearch__.index_document if sn.crop }
|
||||
belongs_to :crop
|
||||
belongs_to :creator, :class_name => 'Member'
|
||||
end
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
class ScientificNameSweeper < ActionController::Caching::Sweeper
|
||||
observe ScientificName
|
||||
|
||||
def after_create(scientific_name)
|
||||
expire_fragment("crop_image_#{scientific_name.crop.id}")
|
||||
end
|
||||
|
||||
def after_update(scientific_name)
|
||||
expire_fragment("crop_image_#{scientific_name.crop.id}")
|
||||
end
|
||||
|
||||
def after_destroy(scientific_name)
|
||||
expire_fragment("crop_image_#{scientific_name.crop.id}")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,21 +1,32 @@
|
||||
class Seed < ActiveRecord::Base
|
||||
extend FriendlyId
|
||||
friendly_id :seed_slug, use: :slugged
|
||||
|
||||
attr_accessible :owner_id, :crop_id, :description, :quantity, :plant_before,
|
||||
:tradable_to, :slug
|
||||
friendly_id :seed_slug, use: [:slugged, :finders]
|
||||
|
||||
belongs_to :crop
|
||||
belongs_to :owner, :class_name => 'Member', :foreign_key => 'owner_id'
|
||||
|
||||
default_scope order("created_at desc")
|
||||
default_scope { order("created_at desc") }
|
||||
|
||||
validates :crop, :approved => true
|
||||
|
||||
validates :crop, :presence => {:message => "must be present and exist in our database"}
|
||||
validates :quantity,
|
||||
:numericality => { :only_integer => true },
|
||||
:numericality => {
|
||||
:only_integer => true,
|
||||
:greater_than_or_equal_to => 0 },
|
||||
:allow_nil => true
|
||||
validates :days_until_maturity_min,
|
||||
:numericality => {
|
||||
:only_integer => true,
|
||||
:greater_than_or_equal_to => 0 },
|
||||
:allow_nil => true
|
||||
validates :days_until_maturity_max,
|
||||
:numericality => {
|
||||
:only_integer => true,
|
||||
:greater_than_or_equal_to => 0 },
|
||||
:allow_nil => true
|
||||
|
||||
scope :tradable, where("tradable_to != 'nowhere'")
|
||||
scope :tradable, -> { where("tradable_to != 'nowhere'") }
|
||||
|
||||
TRADABLE_TO_VALUES = %w(nowhere locally nationally internationally)
|
||||
validates :tradable_to, :inclusion => { :in => TRADABLE_TO_VALUES,
|
||||
@@ -23,6 +34,32 @@ class Seed < ActiveRecord::Base
|
||||
:allow_nil => false,
|
||||
:allow_blank => false
|
||||
|
||||
ORGANIC_VALUES = [
|
||||
'certified organic',
|
||||
'non-certified organic',
|
||||
'conventional/non-organic',
|
||||
'unknown']
|
||||
validates :organic, :inclusion => { :in => ORGANIC_VALUES,
|
||||
:message => "You must say whether the seeds are organic or not, or that you don't know" },
|
||||
:allow_nil => false,
|
||||
:allow_blank => false
|
||||
|
||||
GMO_VALUES = [
|
||||
'certified GMO-free',
|
||||
'non-certified GMO-free',
|
||||
'GMO',
|
||||
'unknown']
|
||||
validates :gmo, :inclusion => { :in => GMO_VALUES,
|
||||
:message => "You must say whether the seeds are genetically modified or not, or that you don't know" },
|
||||
:allow_nil => false,
|
||||
:allow_blank => false
|
||||
|
||||
HEIRLOOM_VALUES = %w(heirloom hybrid unknown)
|
||||
validates :heirloom, :inclusion => { :in => HEIRLOOM_VALUES,
|
||||
:message => "You must say whether the seeds are heirloom, hybrid, or unknown" },
|
||||
:allow_nil => false,
|
||||
:allow_blank => false
|
||||
|
||||
def tradable?
|
||||
if self.tradable_to == 'nowhere'
|
||||
return false
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
class SeedSweeper < ActionController::Caching::Sweeper
|
||||
observe Seed
|
||||
|
||||
def after_create(seed)
|
||||
if seed.tradable? && seed.interesting?
|
||||
expire_fragment('interesting_seeds')
|
||||
end
|
||||
expire_fragment('interesting_members') if seed.owner.interesting?
|
||||
expire_fragment("member_thumbnail_#{seed.owner.id}")
|
||||
end
|
||||
|
||||
def after_update(seed)
|
||||
expire_fragment('interesting_seeds')
|
||||
end
|
||||
|
||||
def after_destroy(seed)
|
||||
if seed.tradable? && seed.interesting?
|
||||
expire_fragment('interesting_seeds')
|
||||
end
|
||||
expire_fragment('interesting_members') if seed.owner.interesting?
|
||||
expire_fragment("member_thumbnail_#{seed.owner.id}")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
7
app/validators/approved_validator.rb
Normal file
7
app/validators/approved_validator.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
class ApprovedValidator < ActiveModel::EachValidator
|
||||
def validate_each(record, attribute, value)
|
||||
unless record.crop.try(:approved?)
|
||||
record.errors[attribute] << (options[:message] || 'must be approved')
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -8,6 +8,7 @@
|
||||
%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
|
||||
|
||||
%h2 Orders
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
- content_for :title, "Linked accounts on other sites"
|
||||
|
||||
- if @authentications
|
||||
- unless @authentications.empty?
|
||||
.authentications
|
||||
- @authentications.each do |authentication|
|
||||
%a{ :href => "http://twitter.com/#{authentication.name}" }
|
||||
.authentication
|
||||
= image_tag "#{authentication.provider}_64.png", :size => "64x64"
|
||||
.provider
|
||||
= authentication.provider.titleize
|
||||
.name
|
||||
= authentication.name
|
||||
= link_to "X", authentication, :confirm => "Are you sure you want to remove this authentication?", :method => :delete, :class => "remove"
|
||||
.clear
|
||||
%p
|
||||
%strong Link another external account:
|
||||
- else
|
||||
%p
|
||||
%strong Link to an external account:
|
||||
|
||||
= link_to image_tag("twitter_64.png", :size => "64x64"), "/auth/twitter", :class => "auth_provider"
|
||||
@@ -1,4 +1,4 @@
|
||||
%h4 Find seeds
|
||||
%h4 Find #{ crop.name } seeds
|
||||
- if crop.seeds.empty?
|
||||
%p
|
||||
There are no seeds available to trade.
|
||||
|
||||
@@ -6,40 +6,87 @@
|
||||
- @crop.errors.full_messages.each do |msg|
|
||||
%li= msg
|
||||
|
||||
%p
|
||||
%span.help-block
|
||||
For detailed crop wrangling guidelines, please consult the
|
||||
=link_to "crop wrangling guide", "http://wiki.growstuff.org/index.php/Crop_wrangling"
|
||||
on the Growstuff wiki.
|
||||
- if can? :wrangle, @crop
|
||||
%p
|
||||
%span.help-block
|
||||
For detailed crop wrangling guidelines, please consult the
|
||||
|
||||
=link_to "crop wrangling guide", "http://wiki.growstuff.org/index.php/Crop_wrangling"
|
||||
on the Growstuff wiki.
|
||||
|
||||
.form-group
|
||||
= f.label :name, :class => 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= f.text_field :name, :class => 'form-control'
|
||||
%span.help-block Name in US English; singular; capitalize proper nouns only.
|
||||
%span.help-block
|
||||
- if can? :wrangle, @crop
|
||||
Name in US English; singular; capitalize proper nouns only.
|
||||
- else
|
||||
Please provide the common name for the crop, in English, if you know it.
|
||||
|
||||
.form-group
|
||||
= f.label :en_wikipedia_url, 'Wikipedia URL', :class => 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= f.text_field :en_wikipedia_url, :class => 'form-control'
|
||||
%span.help-block Link to this crop's page on the English language Wikipedia.
|
||||
.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')
|
||||
%span.help-block Optional. For setting up crop hierarchies for varieties etc.
|
||||
%p
|
||||
%span.help-block
|
||||
You may enter up to 3 scientific names for a crop. Most crops will have only one.
|
||||
= f.fields_for :scientific_names do |sn|
|
||||
%span.help-block
|
||||
- if can? :wrangle, @crop
|
||||
Link to this crop's page on the English language Wikipedia.
|
||||
- else
|
||||
Please provide a link to the crop's page on the English language Wikipedia. Crops without Wikipedia pages cannot be added to our database at this time.
|
||||
|
||||
- if can? :wrangle, @crop
|
||||
|
||||
.form-group
|
||||
= sn.label :scientific_name, "Scientific name", :class => 'control-label col-md-2'
|
||||
= f.label :parent_id, 'Parent crop', :class => 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= sn.text_field :scientific_name, :class => 'form-control'
|
||||
.col-md-2
|
||||
- if sn.object && sn.object.persisted?
|
||||
%label.checkbox
|
||||
= sn.check_box :_destroy
|
||||
= sn.label :_destroy, "Delete"
|
||||
= collection_select(:crop, :parent_id, Crop.all, :id, :name, {:include_blank => true}, :class => 'form-control')
|
||||
%span.help-block Optional. For setting up crop hierarchies for varieties etc.
|
||||
|
||||
%p
|
||||
%span.help-block
|
||||
You may enter up to 3 scientific names for a crop. Most crops will have only one.
|
||||
= f.fields_for :scientific_names do |sn|
|
||||
.form-group
|
||||
= sn.label :scientific_name, "Scientific name", :class => 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= sn.text_field :scientific_name, :class => 'form-control'
|
||||
.col-md-2
|
||||
- if sn.object && sn.object.persisted?
|
||||
%label.checkbox
|
||||
= sn.check_box :_destroy
|
||||
= sn.label :_destroy, "Delete"
|
||||
|
||||
- unless @crop.new_record?
|
||||
.form-group
|
||||
= f.label :approval_status, 'Approval Status', :class=> 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= f.select(:approval_status, @crop.approval_statuses, {}, {:class => 'form-control'})
|
||||
|
||||
.form-group
|
||||
= f.label :reason_for_rejection, 'Reason for rejection', :class => 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= f.select(:reason_for_rejection, @crop.reasons_for_rejection, {:include_blank => true}, {:class => 'form-control'})
|
||||
%p
|
||||
%span.help-block
|
||||
Please provide additional notes why this crop request was rejected if the above reasons do not apply.
|
||||
|
||||
.form-group
|
||||
= f.label :rejection_notes, 'Rejection Notes', :class => 'control-label col-md-2'
|
||||
.col-md-8= f.text_area :rejection_notes, :rows => 6, :class => 'form-control'
|
||||
|
||||
- else
|
||||
%p
|
||||
%span.help-block
|
||||
Provide any additional information that might help us assess your request.
|
||||
|
||||
.form-group
|
||||
= f.label :request_notes, 'Comments', :class => 'control-label col-md-2'
|
||||
.col-md-8= f.text_area :request_notes, :rows => 6, :class => 'form-control'
|
||||
|
||||
%p
|
||||
%span.help-block
|
||||
When you submit this form, your suggestion will be sent to our team of #{link_to 'volunteer crop wranglers', 'http://talk.growstuff.org/c/crop-wrangling'} for review. We'll let you know the outcome as soon as we can.
|
||||
|
||||
.form-group
|
||||
.form-actions.col-md-offset-2.col-md-8
|
||||
= f.submit 'Save', :class => 'btn btn-primary'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%h4 Harvests
|
||||
%h4 #{ crop.name.capitalize } harvests
|
||||
- if crop.harvests.empty?
|
||||
%p
|
||||
Nobody has harvested this crop yet.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
- cache "crop_image_#{crop.id}" do
|
||||
- cache crop do
|
||||
= link_to |
|
||||
image_tag( |
|
||||
crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png', |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.well
|
||||
.row
|
||||
.col-md-4
|
||||
= link_to image_tag((crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png'), :alt => '', :class => 'img-rounded crop-image'), crop
|
||||
= link_to image_tag((crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png'), :alt => '', :class => 'img crop-image'), crop
|
||||
.col-md-8
|
||||
%h3{:style => 'padding-top: 0px; margin-top: 0px'}
|
||||
= link_to crop, crop
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%h4 Plantings
|
||||
%h4 See who's planted #{ crop.name.pluralize }
|
||||
- if crop.plantings.empty?
|
||||
%p
|
||||
Nobody has planted this crop yet.
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
.thumbnail(style='height: 220px')
|
||||
- if crop
|
||||
= link_to image_tag((crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png'), :alt => crop.name, :class => 'img-rounded'), crop
|
||||
%p.crop-name
|
||||
= link_to crop.name, crop
|
||||
- if crop.scientific_names.count > 0
|
||||
%br/
|
||||
%i.scientific-name
|
||||
%small
|
||||
.thumbnail
|
||||
.crop-thumbnail
|
||||
- if crop
|
||||
= link_to image_tag((crop.default_photo ? crop.default_photo.thumbnail_url : 'placeholder_150.png'), :alt => crop.name, :class => 'img'), crop
|
||||
.cropinfo
|
||||
.cropname
|
||||
= link_to crop.name, crop
|
||||
- if crop.scientific_names.count > 0
|
||||
.scientificname
|
||||
= crop.scientific_names.first.scientific_name
|
||||
%br/
|
||||
%small
|
||||
.plantingcount
|
||||
Planted
|
||||
= pluralize(crop.plantings.size, "time")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
- content_for :title, "Editing crop"
|
||||
- content_for :title, "Review crop: #{@crop.name}"
|
||||
|
||||
%p
|
||||
Added by
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
= succeed "." do
|
||||
= link_to "crops database", crops_path
|
||||
|
||||
- cache("full_crop_hierarchy") do
|
||||
- cache cache_key_for(Crop) do
|
||||
= render :partial => "hierarchy", :locals => { :display_crops => @crops }
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
- content_for :title, "Crops"
|
||||
- content_for :title, "Browse crops"
|
||||
- content_for :subtitle, "#{@crops.size} total"
|
||||
|
||||
- if can? :wrangle, Crop
|
||||
= link_to 'Wrangle Crops', wrangle_crops_path, :class => 'btn btn-primary'
|
||||
%p
|
||||
#{ENV['GROWSTUFF_SITE_NAME']} tracks who's growing what, where.
|
||||
View any crop page to see which of our members have planted it and find
|
||||
@@ -12,11 +15,10 @@
|
||||
= submit_tag "Show", :class => 'btn btn-primary'
|
||||
|
||||
%div.pagination
|
||||
= page_entries_info @crops, :model => "crops"
|
||||
= will_paginate @crops
|
||||
= will_paginate @paginated_crops
|
||||
|
||||
.row
|
||||
- @crops.each do |crop|
|
||||
- @paginated_crops.each do |crop|
|
||||
.col-md-2.six-across
|
||||
= render :partial => "thumbnail", :locals => { :crop => crop }
|
||||
|
||||
@@ -25,8 +27,7 @@
|
||||
= link_to 'New Crop', new_crop_path, {:class => 'btn btn-primary'}
|
||||
|
||||
%div.pagination
|
||||
= page_entries_info @crops, :model => "crops"
|
||||
= will_paginate @crops
|
||||
= will_paginate @paginated_crops
|
||||
|
||||
|
||||
%ul.list-inline
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
- content_for :title, "New crop"
|
||||
- content_for :title, (can?(:wrangle, @crop) ? "New crop" : "Suggest a crop")
|
||||
|
||||
- unless can? :wrangler, @crop
|
||||
|
||||
%p Thanks for taking the time to suggest a crop! Our crop database is managed by volunteers, and we appreciate your help. Here are some things to consider when suggesting a new crop:
|
||||
|
||||
%ul
|
||||
%li First, you might want to #{link_to 'search our crops', crops_search_path} to make sure we don't have it already, perhaps under an alternate name.
|
||||
|
||||
%li The Growstuff database only contains edible crops. In future we hope to support other crops, but for now, if your suggestion is not edible we won't be able to add it.
|
||||
|
||||
%li At this time, we are only adding crops which have a Wikipedia page. If you want to add a specific variety of crop that doesn't have its own Wikipedia entry, please use the more general form of the crop instead and put the name of your variety in the notes/description.
|
||||
|
||||
= render 'form'
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
- content_for :title, "Crops matching #{@search}"
|
||||
- if @search
|
||||
- content_for :title, "Crops matching \"#{@search}\""
|
||||
- if @all_matches
|
||||
- content_for :subtitle, "#{@all_matches.size} total"
|
||||
- else
|
||||
- content_for :title, "Crop search"
|
||||
|
||||
- unless (@exact_match || @partial_matches.length > 0)
|
||||
%div
|
||||
= form_tag crops_search_path, :method => :get, :id => 'crop-search', :class => 'form-inline' do
|
||||
.form-group
|
||||
= label_tag :search, "Search crops:", :class => 'sr-only'
|
||||
= text_field_tag 'search', nil, :class => 'search-query input-medium form-control', :placeholder => 'Search crops', :value => @search
|
||||
= submit_tag "Search", :class => 'btn btn-primary'
|
||||
|
||||
- if @all_matches.empty?
|
||||
%h2 No results found
|
||||
%p
|
||||
Sorry, we couldn't find any crops that matched your search for "#{@search}".
|
||||
@@ -9,18 +21,15 @@
|
||||
= link_to "browsing our crop database", crops_path
|
||||
instead.
|
||||
|
||||
- if @exact_match
|
||||
%div#exact_match
|
||||
%h2 Exact match
|
||||
- else
|
||||
%div.pagination
|
||||
= will_paginate @paginated_matches
|
||||
|
||||
%div#paginated_matches
|
||||
.row
|
||||
.col-md-2.six-across
|
||||
= render :partial => "thumbnail", :locals => { :crop => @exact_match }
|
||||
|
||||
- if ! @partial_matches.empty?
|
||||
%div#partial_matches
|
||||
%h2 Partial matches
|
||||
.row
|
||||
- @partial_matches.each do |c|
|
||||
- @paginated_matches.each do |c|
|
||||
.col-md-2.six-across
|
||||
= render :partial => "thumbnail", :locals => { :crop => c }
|
||||
|
||||
%div.pagination
|
||||
= will_paginate @paginated_matches
|
||||
|
||||
@@ -1,18 +1,34 @@
|
||||
- content_for :title, @crop.name
|
||||
- content_for :subtitle, @crop.default_scientific_name
|
||||
- content_for :buttonbar do
|
||||
- if can? :create, Planting
|
||||
= link_to "Plant this", new_planting_path(:crop_id => @crop.id), :class => 'btn btn-default'
|
||||
|
||||
- if can? :create, Harvest
|
||||
= link_to "Harvest this", new_harvest_path(:crop_id => @crop.id), :class => 'btn btn-default'
|
||||
- if @crop.pending?
|
||||
.alert.alert-danger
|
||||
%b This crop is currently pending approval.
|
||||
%p This crop was requested by #{@crop.requester} #{time_ago_in_words(@crop.created_at)} ago.
|
||||
- unless @crop.request_notes.blank?
|
||||
%p
|
||||
Request notes: #{@crop.request_notes}
|
||||
|
||||
- if can? :create, Seed
|
||||
= link_to 'Add seeds to stash', new_seed_path(:params => { :crop_id => @crop.id }), :class => 'btn btn-default'
|
||||
- if @crop.rejected?
|
||||
.alert.alert-danger
|
||||
%b This crop was rejected for the following reason: #{@crop.reason_for_rejection == "other" ? @crop.rejection_notes : @crop.reason_for_rejection}.
|
||||
|
||||
- if @crop.approved?
|
||||
- content_for :buttonbar do
|
||||
- if can? :create, Planting
|
||||
= link_to "Plant this", new_planting_path(:crop_id => @crop.id), :class => 'btn btn-default'
|
||||
|
||||
- if can? :create, Harvest
|
||||
= link_to "Harvest this", new_harvest_path(:crop_id => @crop.id), :class => 'btn btn-default'
|
||||
|
||||
- if can? :create, Seed
|
||||
= link_to 'Add seeds to stash', new_seed_path(:params => { :crop_id => @crop.id }), :class => 'btn btn-default'
|
||||
|
||||
|
||||
.row
|
||||
.col-md-9
|
||||
- unless current_member
|
||||
Learn how to grow #{ @crop.name.pluralize } from growers around the world. #{ ENV['GROWSTUFF_SITE_NAME'] } has tips and advice from real-life growers, including when to plant #{ @crop.name.pluralize }, how to harvest #{ @crop.name.pluralize }, and more.
|
||||
|
||||
= render :partial => 'photos', :locals => { :crop => @crop }
|
||||
|
||||
@@ -35,38 +51,48 @@
|
||||
%div#cropmap
|
||||
|
||||
%a{:name => 'posts'}
|
||||
%div.pagination
|
||||
= page_entries_info @posts, :model => "posts"
|
||||
= will_paginate @posts, :params => {:anchor => "posts"}
|
||||
%h2 What people are saying about #{ @crop.name.pluralize }
|
||||
|
||||
- unless @posts.empty?
|
||||
- if @posts.empty?
|
||||
%p
|
||||
Nobody has posted about #{ @crop.name.pluralize } yet.
|
||||
%p
|
||||
- if can? :create, Post
|
||||
= link_to "Post something", new_post_path, :class => 'btn btn-default'
|
||||
- else
|
||||
= render :partial => "shared/signin_signup", :locals => { :to => "post your tips and experiences growing #{ @crop.name.pluralize }" }
|
||||
- else
|
||||
%div.pagination
|
||||
= page_entries_info @posts, :model => "posts"
|
||||
= will_paginate @posts, :params => {:anchor => "posts"}
|
||||
- @posts.each do |post|
|
||||
= render :partial => "posts/single", :locals => { :post => post, :subject => true }
|
||||
|
||||
%div.pagination
|
||||
= page_entries_info @posts, :model => "posts"
|
||||
= will_paginate @posts, :params => {:anchor => "posts"}
|
||||
%div.pagination
|
||||
= page_entries_info @posts, :model => "posts"
|
||||
= will_paginate @posts, :params => {:anchor => "posts"}
|
||||
|
||||
.col-md-3
|
||||
|
||||
= render :partial => 'wrangle', :locals => { :crop => @crop }
|
||||
= render :partial => 'scientific_names', :locals => { :crop => @crop }
|
||||
= render :partial => 'alternate_names', :locals => { :crop => @crop }
|
||||
|
||||
%h4 Planting advice
|
||||
%h4 How to grow #{ @crop.name.pluralize }
|
||||
|
||||
= render :partial => 'grown_for', :locals => { :crop => @crop }
|
||||
= render :partial => 'planting_advice', :locals => { :crop => @crop }
|
||||
|
||||
%h4 Varieties
|
||||
= render :partial => 'scientific_names', :locals => { :crop => @crop }
|
||||
= render :partial => 'alternate_names', :locals => { :crop => @crop }
|
||||
|
||||
%h4 #{ @crop.name.capitalize } varieties
|
||||
= render :partial => 'varieties', :locals => { :crop => @crop }
|
||||
|
||||
|
||||
%h4 More information
|
||||
%ul
|
||||
%li= link_to 'Wikipedia (English)', @crop.en_wikipedia_url
|
||||
|
||||
= render :partial => 'plantings', :locals => { :crop => @crop }
|
||||
= render :partial => 'harvests', :locals => { :crop => @crop }
|
||||
= render :partial => 'find_seeds', :locals => { :crop => @crop }
|
||||
|
||||
|
||||
%h4 Learn more about #{ @crop.name.pluralize }
|
||||
%ul
|
||||
%li= link_to 'Wikipedia (English)', @crop.en_wikipedia_url
|
||||
|
||||
|
||||
@@ -15,18 +15,38 @@
|
||||
%li.crop_wrangler
|
||||
= link_to crop_wrangler.login_name, crop_wrangler
|
||||
|
||||
%h2 Recently added crops
|
||||
.tabbable
|
||||
%ul.nav.nav-tabs
|
||||
%li{:class => @approval_status.blank? ? 'active' : ''}
|
||||
= link_to "Recently added", wrangle_crops_path
|
||||
%li{:class => @approval_status == "pending" ? 'active' : ''}
|
||||
= link_to "Pending approval", wrangle_crops_path(:approval_status => "pending")
|
||||
%li{:class => @approval_status == "rejected" ? 'active' : ''}
|
||||
= link_to "Rejected", wrangle_crops_path(:approval_status => "rejected")
|
||||
|
||||
%h2
|
||||
- if @approval_status == "pending"
|
||||
Requested Crops
|
||||
- elsif @approval_status == "rejected"
|
||||
Rejected Crops
|
||||
- else
|
||||
Recently added crops
|
||||
|
||||
|
||||
%div.pagination
|
||||
= page_entries_info @crops, :model => "crops"
|
||||
= will_paginate @crops
|
||||
|
||||
%table.table.table-striped
|
||||
%table{:class => "table table-striped", :id => @approval_status.blank? ? 'recently-added-crops' : "#{@approval_status}-crops"}
|
||||
%tr
|
||||
%th System name
|
||||
%th English Wikipedia URL
|
||||
%th Scientific names
|
||||
%th Added by
|
||||
%th Requested by
|
||||
- if @approval_status == "rejected"
|
||||
%th Rejected by
|
||||
- if @approval_status != "rejected" && @approval_status != "pending"
|
||||
%th Added by
|
||||
%th When
|
||||
- @crops.each do |c|
|
||||
%tr
|
||||
@@ -36,7 +56,9 @@
|
||||
- c.scientific_names.each do |s|
|
||||
= link_to s.scientific_name, s
|
||||
%br/
|
||||
%td= link_to c.creator, c.creator
|
||||
%td= c.requester.present? ? (link_to c.requester, c.requester) : "N/A"
|
||||
- unless @approval_status == "pending"
|
||||
%td= c.creator.present? ? (link_to c.creator, c.creator) : "N/A"
|
||||
%td
|
||||
= distance_of_time_in_words(c.created_at, Time.zone.now)
|
||||
ago.
|
||||
@@ -44,3 +66,5 @@
|
||||
%div.pagination
|
||||
= page_entries_info @crops, :model => "crops"
|
||||
= will_paginate @crops
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,21 @@
|
||||
:growstuff_markdown
|
||||
#{strip_tags @garden.description}
|
||||
|
||||
- if @garden.photos.count > 0 or (can? :edit, @garden and can? :create, Photo)
|
||||
.row
|
||||
%h2 Photos
|
||||
|
||||
%ul.thumbnails
|
||||
- @garden.photos.each do |p|
|
||||
.col-md-2.six-across
|
||||
= render :partial => 'photos/thumbnail', :locals => { :photo => p }
|
||||
- if can? :create, Photo and can? :edit, @garden
|
||||
.col-md-2
|
||||
.thumbnail(style='height: 220px')
|
||||
%p{:style => 'text-align: center; padding-top: 50px'}
|
||||
= link_to "Add photo", new_photo_path(:type => "garden", :id => @garden.id), :class => 'btn btn-primary'
|
||||
|
||||
|
||||
%h3
|
||||
What's planted here?
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ csv.headers :id,
|
||||
:unit,
|
||||
:weight_quantity,
|
||||
:weight_unit,
|
||||
:si_weight,
|
||||
:date_harvested,
|
||||
:description,
|
||||
:date_added,
|
||||
@@ -31,7 +32,7 @@ csv.headers :id,
|
||||
csv.cell :plant_part_id, h.plant_part ? h.plant_part.id : ''
|
||||
csv.cell :plant_part_name, h.plant_part ? h.plant_part.to_s : ''
|
||||
|
||||
csv.cells :quantity, :unit, :weight_quantity, :weight_unit
|
||||
csv.cells :quantity, :unit, :weight_quantity, :weight_unit, :si_weight
|
||||
|
||||
csv.cell :date_harvested, h.created_at.to_s(:db)
|
||||
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
.row
|
||||
.col-md-6.hidden-xs
|
||||
- cache "interesting_crops", :expires_in => 1.day do
|
||||
.col-md-8
|
||||
- cache cache_key_for(Crop, 'interesting'), :expires_in => 1.day do
|
||||
%h2= t('.our_crops')
|
||||
- Crop.interesting.each do |c|
|
||||
.col-md-3{:style => 'margin:0px; padding: 3px'}
|
||||
= render :partial => 'crops/image_with_popover', :locals => { :crop => c }
|
||||
.hidden-xs
|
||||
- Crop.interesting.first(8).each do |c|
|
||||
.col-md-3
|
||||
= render :partial => 'crops/thumbnail', :locals => { :crop => c }
|
||||
.visible-xs
|
||||
- Crop.interesting.first(3).each do |c|
|
||||
.col-md-3
|
||||
= render :partial => 'crops/thumbnail', :locals => { :crop => c }
|
||||
|
||||
.col-md-6
|
||||
- cache "interesting_plantings" do
|
||||
.col-md-4.hidden-xs
|
||||
- cache cache_key_for(Planting) do
|
||||
%h2= t('.recently_planted')
|
||||
= render :partial => 'plantings/list', :locals => { :plantings => Planting.interesting.first(4) }
|
||||
= render :partial => 'plantings/list', :locals => { :plantings => Planting.interesting.first(6) }
|
||||
|
||||
.row
|
||||
.col-md-12
|
||||
- cache "recent_crops" do
|
||||
- cache cache_key_for(Crop, 'recent') do
|
||||
%p{ :style => 'margin-top: 11.25px' }
|
||||
%strong
|
||||
#{t('.recently_added')}:
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
%h2= t('.discussion')
|
||||
|
||||
- cache "recent_posts" do
|
||||
- posts = Post.limit(6)
|
||||
- if posts
|
||||
=render :partial => "posts/summary", :locals => { :posts => posts, :howmany => 6 }
|
||||
- posts = Post.limit(6)
|
||||
- if posts
|
||||
=render :partial => "posts/summary", :locals => { :posts => posts, :howmany => 6 }
|
||||
|
||||
- cache "homepage_forums" do
|
||||
- cache cache_key_for(Forum) do
|
||||
- forums = Forum.all
|
||||
- if forums
|
||||
%ul.list-inline
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
%h2= t('.keep_in_touch')
|
||||
|
||||
%p
|
||||
= link_to(image_tag("twitter_32.png", :alt => ''), 'http://twitter.com/growstufforg', :target => "_blank")
|
||||
= t('.twitter_html', link: link_to(t('.twitter_linktext'), 'http://twitter.com/growstufforg', :target => "_blank"))
|
||||
|
||||
%p
|
||||
= link_to(image_tag("facebook_32.png", :alt => ''), 'https://www.facebook.com/Growstufforg', :target => "_blank")
|
||||
= t('.facebook_html', link: link_to(t('.facebook_linktext'), 'https://www.facebook.com/Growstufforg', :target => "_blank"))
|
||||
|
||||
%p
|
||||
= link_to(image_tag("blog_32.png", :alt => ''), 'http://blog.growstuff.org/', :target => "_blank")
|
||||
= t('.blog_html', link: link_to(t('.blog_linktext'), 'http://blog.growstuff.org/', :target => "_blank"))
|
||||
|
||||
%p
|
||||
= link_to(image_tag("email_32.png", :alt => ''), 'http://blog.growstuff.org/newsletter', :target => "_blank")
|
||||
= t('.newsletter_html', link: link_to(t('.newsletter_linktext'), 'http://blog.growstuff.org/newsletter', :target => "_blank"))
|
||||
@@ -1,4 +1,4 @@
|
||||
- cache "interesting_members" do
|
||||
- cache cache_key_for(Member) do
|
||||
.hidden-xs
|
||||
- members = Member.interesting.first(6)
|
||||
- if members.present?
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
.row
|
||||
- members.each do |m|
|
||||
.col-md-6.homepage-members
|
||||
.col-md-4.homepage-members
|
||||
= render :partial => "members/thumbnail", :locals => { :member => m }
|
||||
|
||||
%p.text-right
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
%h2= t('.open_source_title')
|
||||
|
||||
%p
|
||||
= t('.open_source_body_html', why: link_to(t('.why_linktext'), 'http://blog.growstuff.org/2013/02/20/why-growstuff-is-open-source/'),
|
||||
github: link_to(t('.github_linktext'), 'http://github.com/Growstuff/growstuff'),
|
||||
site_name: ENV['GROWSTUFF_SITE_NAME'] )
|
||||
|
||||
|
||||
%h2= t('.open_data_title')
|
||||
|
||||
%p
|
||||
= t('.open_data_body_html', creative_commons_link: link_to(t('.creative_commons_linktext'), 'http://creativecommons.org/licenses/by-sa/3.0/'),
|
||||
wiki_link: link_to(t('.wiki_linktext'), 'http://wiki.growstuff.org/index.php/Open_data'),
|
||||
api_docs_link: link_to(t('.api_docs_linktext'), 'http://wiki.growstuff.org/index.php/API'))
|
||||
|
||||
|
||||
|
||||
%h2= t('.get_involved_title')
|
||||
|
||||
%p
|
||||
= t('.get_involved_body_html', talk_link: link_to(t('.talk_linktext'), 'http://talk.growstuff.org/'),
|
||||
wiki_link: link_to(t('.wiki_linktext'), 'http://wiki.growstuff.org/'))
|
||||
|
||||
|
||||
%h2= t('.support_title')
|
||||
|
||||
%p
|
||||
= t('.support_body_html', ad_free: link_to(t('.ad_free_linktext'), 'http://wiki.growstuff.org/index.php/Why_no_ads%3F'),
|
||||
buy_account: link_to(t('.buy_account_linktext'), shop_path))
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
%h2= t('.title')
|
||||
|
||||
- cache "interesting_seeds" do
|
||||
- cache cache_key_for(Seed) do
|
||||
- if seeds.length > 0
|
||||
|
||||
%table.table.table-striped
|
||||
|
||||
@@ -17,13 +17,9 @@
|
||||
= render :partial => 'blurb'
|
||||
.visible-xs
|
||||
= render :partial => 'blurb'
|
||||
.row
|
||||
.col-md-8.main
|
||||
|
||||
= render :partial => 'crops'
|
||||
= render :partial => 'seeds'
|
||||
= render :partial => 'members'
|
||||
= render :partial => 'discuss'
|
||||
|
||||
.col-md-4.sidebar
|
||||
= render :partial => 'keep_in_touch'
|
||||
= render :partial => 'open'
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
.navbar.navbar-default.navbar-bottom
|
||||
.container
|
||||
%ul.nav.navbar-nav.text-center
|
||||
%li= link_to "About", "http://wiki.growstuff.org/index.php/About%20Growstuff"
|
||||
%li= link_to "Contact", url_for(:controller => '/about', :action => 'contact')
|
||||
%li= link_to "Terms of Service", url_for(:controller => '/policy', :action => 'tos')
|
||||
%li= link_to "Privacy Policy", url_for(:controller => %'/policy', :action => 'privacy')
|
||||
%li= link_to "Community Guidelines", url_for(:controller => '/policy', :action => 'community')
|
||||
%li= link_to "Support/FAQ", url_for(:controller => '/support')
|
||||
%li= link_to "Open Source", "https://github.com/Growstuff/growstuff"
|
||||
.row
|
||||
.col-md-4#about-growstuff
|
||||
!= cms_snippet_content(:footer1)
|
||||
.col-md-4#policies
|
||||
!= cms_snippet_content(:footer2)
|
||||
.col-md-4#contact
|
||||
!= cms_snippet_content(:footer3)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
%span.icon-bar
|
||||
%span.icon-bar
|
||||
%a.navbar-brand(href=root_path)
|
||||
= image_tag("/assets/growstuff-brand.png", :size => "200x50", :alt => ENV['GROWSTUFF_SITE_NAME'])
|
||||
= image_tag("growstuff-brand.png", :size => "200x50", :alt => ENV['GROWSTUFF_SITE_NAME'])
|
||||
.navbar-collapse.collapse#navbar-collapse
|
||||
%ul.nav.navbar-nav
|
||||
%li.dropdown<
|
||||
@@ -65,12 +65,14 @@
|
||||
%li= link_to "Sign out", destroy_member_session_path, :method => :delete
|
||||
|
||||
- else
|
||||
%li= link_to 'Sign in', new_member_session_path
|
||||
%li= link_to 'Sign up', new_member_registration_path
|
||||
%li= link_to 'Sign in', new_member_session_path, :id => 'navbar-signin'
|
||||
%li= link_to 'Sign up', new_member_registration_path, :id => 'navbar-signup'
|
||||
|
||||
= form_tag crops_search_path, :method => :get, :class => 'navbar-form pull-right' do
|
||||
= form_tag crops_search_path, :method => :get, :id => 'navbar-search', :class => 'navbar-form pull-right' do
|
||||
.input
|
||||
= label_tag :search, "Search crop database:", :class => 'sr-only'
|
||||
= text_field_tag 'search', nil, :class => 'search-query input-medium form-control', :placeholder => 'Search crops'
|
||||
= submit_tag "Search", :class => 'btn sr-only'
|
||||
|
||||
- # anchor tag for accessibility link to skip the navigation menu
|
||||
%a{:name => 'skipnav'}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user