Compare commits

..

7 Commits

Author SHA1 Message Date
Skud
d066801943 Merge pull request #616 from pmackay/api_v1
Api v1 - initial start
2015-01-13 10:50:01 +11:00
Paul Mackay
016feaf8bf #582: Change license checks to expect() syntax. 2015-01-12 10:25:00 +00:00
Paul Mackay
1b5d2bb898 #582: Fixes for review comments. 2015-01-11 19:25:40 +00:00
Paul Mackay
a3e3abecf3 Merge api-v1-jbuilder into new API branch. 2015-01-07 08:41:26 +00:00
Paul Mackay
223a06ef8b Some crop API tweaks, basic LD stuff. 2014-11-07 07:03:27 +00:00
Paul Mackay
f3eb5774ef Add spec test for 2 crop API calls, including license. 2014-11-03 16:45:37 +00:00
Paul Mackay
800a1f10e3 First commit for v1 API implementation based on jbuilder. 2014-11-03 15:03:59 +00:00
1130 changed files with 62759 additions and 20562 deletions

View File

@@ -1,44 +0,0 @@
engines:
rubocop:
enabled: true
scss-lint:
enabled: true
shellcheck:
enabled: true
eslint:
enabled: true
coffeelint:
enabled: true
brakeman:
enabled: true
bundler-audit:
enabled: true
duplication:
enabled: true
config:
languages:
- ruby
- javascript
exclude_fingerprints:
- 16dbcb58d6caa7ccfe241417831ecfa6
- 7d7dca4f27f50e3084f203280073cc74
fixme:
enabled: true
exclude_fingerprints: # rubocop_todo filename
- 63b8552079d106832fbe281566b6d028
- d38afbaaea3ecaa9a4cf046b07a01cec
- 57ff3968fd371d3e1f75c237d6c78acf
ratings:
paths:
- "**.rb"
- "**.js"
- "**.coffee"
- "**.sass"
- "**.haml"
- Gemfile.lock
exclude_paths:
- config/
- db/
- spec/
- public/
- app/assets/stylesheets/bootstrap-accessibility.css

4
.gitignore vendored
View File

@@ -8,12 +8,8 @@ coverage
*~
*.DS_Store
config/application.yml
config/database.yml
credentials*.sh
Pathogen:
custom_plan.rb
zeus.json
.bundle
.idea/**
public/**
node_modules

View File

@@ -1,9 +0,0 @@
linters:
LineLength:
max: 120
InstanceVariables:
enabled: false
IdNames:
enabled: false
ConsecutiveComments:
enabled: false

View File

@@ -1,10 +0,0 @@
---
fail_on_violations: true
ruby:
config_file: .rubocop.yml
haml:
config_file: .haml-lint.yml
scss:
config_file: .scss-lint.yml
eslint:
config_file: .eslintrc

View File

@@ -1,3 +0,0 @@
{
"userBlacklist": ["tygriffin","oshiho3"]
}

View File

@@ -1,100 +0,0 @@
---
# Use this file to configure the Overcommit hooks you wish to use. This will
# extend the default configuration defined in:
# https://github.com/brigade/overcommit/blob/master/config/default.yml
#
# At the topmost level of this YAML file is a key representing type of hook
# being run (e.g. pre-commit, commit-msg, etc.). Within each type you can
# customize each hook, such as whether to only run it on certain files (via
# `include`), whether to only display output if it fails (via `quiet`), etc.
#
# For a complete list of hooks, see:
# https://github.com/brigade/overcommit/tree/master/lib/overcommit/hook
#
# For a complete list of options that you can use to customize hooks, see:
# https://github.com/brigade/overcommit#configuration
#
# Uncomment the following lines to make the configuration take effect.
PreCommit:
ALL:
quiet: false
problem_on_unmodified_line: warn
RuboCop:
enabled: true
command: ['bundle', 'exec', 'rubocop', '-D', '--rails']
TrailingWhitespace:
enabled: true
exclude:
- '**/db/structure.sql' # Ignore trailing whitespace in generated files
CoffeeLint:
enabled: true
on_fail: warn
command: ['npm', 'run', 'coffeelint']
required_executable: 'npm'
HardTabs:
enabled: true
AuthorEmail:
enabled: false
AuthorName:
enabled: false
CssLint:
enabled: true
exclude:
- '**/bootstrap.min.css'
command: ['npm', 'run', 'csslint']
required_executable: 'npm'
HamlLint:
enabled: true
command: ['bundle', 'exec', 'haml-lint', 'app/views']
JsonSyntax:
enabled: true
BundleOutdated:
enabled: true
on_warn: warn
BundleAudit:
enabled: true
on_warn: warn
JsHint:
enabled: true
exclude:
- 'app/assets/**'
- 'spec/javascripts/support/vendor/**'
- '**/bootstrap*'
command: ['npm', 'run', 'jshint']
required_executable: 'npm'
ScssLint:
enabled: true
RailsSchemaUpToDate:
enabled: true
MergeConflicts:
enabled: true
YamlLint:
enabled: true
PostCheckout:
ALL:
quiet: false
BundleInstall:
enabled: true
RailsSchemaUpToDate:
enabled: true
PostMerge:
BundleInstall:
enabled: true
RailsSchemaUpToDate:
enabled: true
# PrePush:
# ALL:
# on_warn: fail # Treat all warnings as failures
# quiet: false
# # Brakeman:
# # enabled: true
# RSpec:
# enabled: true
# command: ['bundle', 'exec', 'rspec', '--fail-fast']
#
# IndexTags:
# enabled: true # Generate a tags file with `ctags` each time HEAD changes

1
.rspec
View File

@@ -1,2 +1 @@
--color
--require spec_helper

View File

@@ -1,75 +0,0 @@
inherit_from: .rubocop_todo.yml
AllCops:
Include:
- 'Rakefile'
- 'config.ru'
- 'lib/**/*.rake'
Exclude:
- 'db/schema.rb'
- 'vendor/**/*'
TargetRailsVersion: 4.0
Rails:
Enabled: true
Style/FileName:
Exclude:
- 'Guardfile'
- 'Gemfile'
- 'Gemfile.lock'
Style/StringLiterals:
Enabled: false
# Stop hound and codeclimate fighting
Style/PercentLiteralDelimiters:
PreferredDelimiters:
default: ()
'%i': ()
'%w': ()
Layout/MultilineMethodCallIndentation:
EnforcedStyle: indented
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: with_first_parameter, with_fixed_indentation
Layout/AlignParameters:
EnforcedStyle: with_fixed_indentation
Metrics/LineLength:
Max: 120
# turn these back on in Rails 5
Rails/HttpPositionalArguments: # See https://github.com/bbatsov/rubocop/issues/3629
Enabled: false
Style/Documentation:
Enabled: false
Style/FrozenStringLiteralComment:
Enabled: false
# Configuration parameters: Include.
# Include: app/**/*.rb, config/**/*.rb, db/**/*.rb, lib/**/*.rb
Rails/Output:
Exclude:
- 'config/unicorn.rb'
- 'db/seeds.rb'
Metrics/BlockLength:
Exclude:
- 'spec/**/*'
- '**/*.rake'
- 'config/**/*.rb'
# Remove the following once the code style matches
Metrics/MethodLength:
Max: 34
Metrics/AbcSize:
Max: 31
Metrics/ClassLength:
Max: 179
Metrics/CyclomaticComplexity:
Max: 11
Metrics/PerceivedComplexity:
Max: 9

View File

@@ -1,113 +0,0 @@
# This configuration was generated by
# `rubocop --auto-gen-config --no-offense-counts`
# on 2017-12-06 11:20:15 +1300 using RuboCop version 0.49.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
Lint/HandleExceptions:
Exclude:
- 'lib/tasks/testing.rake'
# Cop supports --auto-correct.
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
Lint/UnusedMethodArgument:
Exclude:
- 'app/controllers/application_controller.rb'
- 'app/controllers/passwords_controller.rb'
- 'app/controllers/registrations_controller.rb'
- 'app/validators/approved_validator.rb'
Rails/FilePath:
Exclude:
- 'spec/rails_helper.rb'
Rails/OutputSafety:
Exclude:
- 'app/helpers/application_helper.rb'
- 'app/helpers/auto_suggest_helper.rb'
- 'app/helpers/gardens_helper.rb'
# Configuration parameters: Blacklist.
# Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters
Rails/SkipsModelValidations:
Exclude:
- 'db/seeds.rb'
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: strict, flexible
Rails/TimeZone:
Exclude:
- 'spec/controllers/accounts_controller_spec.rb'
- 'spec/factories/member.rb'
- 'spec/factories/post.rb'
- 'spec/models/post_spec.rb'
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: always, conditionals
Style/AndOr:
Exclude:
- 'config/unicorn.rb'
- 'lib/tasks/growstuff.rake'
Style/AsciiComments:
Exclude:
- 'config/initializers/comfortable_mexican_sofa.rb'
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: nested, compact
Style/ClassAndModuleChildren:
Exclude:
- 'app/controllers/admin/orders_controller.rb'
- 'lib/actions/oauth_signup_action.rb'
- 'lib/haml/filters/escaped_markdown.rb'
Style/IdenticalConditionalBranches:
Exclude:
- 'app/controllers/follows_controller.rb'
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: line_count_dependent, lambda, literal
Style/Lambda:
Exclude:
- 'spec/controllers/member_controller_spec.rb'
- 'spec/models/photo_spec.rb'
# Cop supports --auto-correct.
Style/MultilineIfModifier:
Exclude:
- 'spec/rails_helper.rb'
# Cop supports --auto-correct.
Style/MutableConstant:
Exclude:
- 'app/models/planting.rb'
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles.
# SupportedStyles: predicate, comparison
Style/NumericPredicate:
Exclude:
- 'spec/**/*'
- 'app/helpers/harvests_helper.rb'
- 'app/helpers/plantings_helper.rb'
- 'lib/tasks/growstuff.rake'
# Cop supports --auto-correct.
Style/ParallelAssignment:
Exclude:
- 'app/mailers/notifier.rb'
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
# SupportedStyles: slashes, percent_r, mixed
Style/RegexpLiteral:
Exclude:
- 'spec/lib/haml/filters/growstuff_markdown_spec.rb'
- 'spec/rails_helper.rb'
- 'spec/views/devise/registrations/edit_spec.rb'
- 'spec/views/members/index.html.haml_spec.rb'
- 'spec/views/posts/index.html.haml_spec.rb'

View File

@@ -1 +1 @@
2.4.1
2.1.5

View File

@@ -1,72 +1,12 @@
sudo: required
---
language: ruby
cache:
bundler: true
directories:
- travis_phantomjs
- tmp/cache/assets/test/sprockets
env:
matrix:
- GROWSTUFF_ELASTICSEARCH='true' RSPEC_TAG=elasticsearch STATIC_CHECKS=false
- GROWSTUFF_ELASTICSEARCH='false' RSPEC_TAG=~elasticsearch STATIC_CHECKS=false
- STATIC_CHECKS=true
global:
- GROWSTUFF_SITE_NAME="Growstuff (travis)"
- RAILS_SECRET_TOKEN='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
- secure: "Z5TpM2jEX4UCvNePnk/LwltQX48U2u9BRc+Iypr1x9QW2o228QJhPIOH39a8RMUrepGnkQIq9q3ZRUn98RfrJz1yThtlNFL3NmzdQ57gKgjGwfpa0e4Dwj/ZJqV2D84tDGjvdVYLP7zzaYZxQcwk/cgNpzKf/jq97HLNP7CYuf4="
before_install:
- ./script/install_phantomjs;
- export PATH=$PWD/travis_phantomjs/phantomjs-2.1.1-linux-x86_64/bin:$PATH
# Force Travis to use Elastic Search 2.4.0
- >
if [ "${GROWSTUFF_ELASTICSEARCH}" = "true" ]; then
sudo dpkg -r elasticsearch;
curl -O https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/deb/elasticsearch/2.4.0/elasticsearch-2.4.0.deb;
sudo dpkg -i --force-confnew elasticsearch-2.4.0.deb;
sudo service elasticsearch start;
sleep 10;
curl localhost:9200;
fi
env: GROWSTUFF_SITE_NAME="Growstuff (travis)" RAILS_SECRET_TOKEN='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
bundler_args: --without development production staging
rvm:
- 2.1.5
before_script:
- set -e
- >
if [ "${STATIC_CHECKS}" = "true" ]; then
./script/install_linters;
else
RAILS_ENV=test bundle exec rake db:create db:migrate;
bundle exec rake assets:precompile;
fi
- set +e
- psql -c 'create database growstuff_test;' -U postgres
script:
- set -e
- >
if [ "${STATIC_CHECKS}" = "true" ]; then
./script/check_static.rb
else
bundle exec rake db:migrate --trace;
bundle exec rspec --tag $RSPEC_TAG spec/;
bundle exec rake jasmine:ci;
fi;
- set +e
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
master: growstuff-prod
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
addons:
code_climate:
repo_token: 462e015bbdaabfb20910fc07f2fea253410ecb131444e00f97dbf32dc6789ca6
- bundle exec rake db:migrate --trace
- bundle exec rspec spec/

View File

@@ -1,7 +0,0 @@
extends: relaxed
rules:
# 80 chars should be enough, but don't fail if a line is longer
line-length:
max: 150
level: warning

View File

@@ -3,36 +3,11 @@ Thanks for contributing to Growstuff!
When you create a pull request, please include the following:
* Mention the issue it solves (eg. #123)
* Your code should follow our [Coding style guide](https://github.com/Growstuff/growstuff/wiki/Development-process-overview#coding-practices)
* 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).
All pull requests should pass our automatic continuous integration and style
checks before being merged. You can run tests locally as follows:
- `rake spec` to run all Ruby tests
- `rake spec:models` to run Ruby model tests (or `rake spec:views` for view tests, etc)
- `rake static` to run all static checks (code style, unfixed Git conflicts, etc)
- `rake jasmine:ci` to run JavaScript unit tests in headless mode
- `rake jasmine` to start a server for running JavaScript unit tests in a
browser (eg for debugging). Point your browser at http://localhost:8888 to
run the tests.
- `rspec ./spec/path/to/my_spec.rb` to run all Ruby tests in the file `my_spec.rb`
- `rspec ./spec/path/to/my_spec.rb:45` to run the Ruby test starting on line 45 of
`my_spec.rb`. RSpec will output a list of command-lines in this form for all
failing tests so you can easily re-run particular ones.
- `rspec --only-failures` to re-run all Ruby tests that failed last time.
Growstuff runs several linters and checkers before a change is merged. These
run from overcommit. To automatically run the same linters yourself you can
install overcommit too.
- `./script/install_linters`
You can run `rake -T` to see a list of available Rake tasks. If you can't get
some tests to pass, please submit a pull request anyway - we'll be happy to
help you debug the failures.
If you would like to discuss an idea before submitting a pull request,
please open a [GitHub Issue](https://github.com/growstuff/growstuff/issues),
where our dev team will be happy to help you.
If you would like to discuss your work before submitting a pull request,
please join any of our [Discussion
forums](http://wiki.growstuff.org/index.php/Discussion_forums), where
our dev team will be happy to help you.

View File

@@ -11,12 +11,10 @@ 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)
- Taylor Griffin / [tygriffin](https://github.com/tygriffin)
- Mackenzie Morgan / [maco](https://github.com/maco)
- Joseph Caudle / [jcaudle](https://github.com/jcaudle)
## 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)
@@ -24,6 +22,7 @@ submit the change with your pull request.
- Maia Sauren / [sauramaia](https://github.com/sauramaia)
- Norman Ancajas / [nbancajas](https://github.com/nbancajas)
- Jonathan "Duke" Leto / [leto](https://github.com/leto)
- Mackenzie Morgan / [maco](https://github.com/maco)
- Amy Hendrix / [sabreuse](https://github.com/sabreuse)
- CephLPod / [cephLpod](https://github.com/cephLpod/)
- Gemma Mason / [gemmaellen](https://github.com/gemmaellen)
@@ -41,6 +40,7 @@ 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,38 +51,4 @@ 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)
- Jake Yesbeck / [yez](https://github.com/yez)
- Mauricio Gonzalez / [mauricio-gonzalez](https://github.com/mauricio-gonzalez)
- Andrey Bazhutkin / [andrba](https://github.com/andrba)
- Gabriel Sandoval / [gabrielsandoval](https://github.com/gabrielsandoval)
- Cjay Billones / [CjayBillones](https://github.com/CjayBillones)
- Katy Ereira / [maccath](https://github.com/maccath)
- Gabrielle DeWitt / [gabrielle27](https://github.com/gabrielle27)
- Manmeet Singh / [manmeetsingh](https://github.com/manmeetsingh)
- Jym Paul Carandang / [jacarandang](https://github.com/jacarandang)
- Anthony Atkinson / [sha1sum](https://github.com/sha1sum)
- Terence Conquest / [twconquest](https://github.com/twconquest)
- Daniel O'Connor / [CloCkWeRX](https://github.com/CloCkWeRX)
- DV Dasari / [dv2](https://github.com/dv2)
- Eric Tillberg / [Thrillberg](https://github.com/Thrillberg)
- Lucas Nogueira / [lucasnogueira](https://github.com/lucasnogueira)
- Charley Lewittes / [ctlewitt](https://github.com/ctlewitt)
- Kristine Nicole Polvoriza / [polveenomials](https://github.com/polveenomials)
- Brenda Wallace / [br3nda](https://github.com/br3nda)
- Jim Stallings / [jestallin](https://github.com/jestallin)
- Alyssa Ransbury / [alran](https://github.com/alran)
- Thomas Countz / [thomascountz](https://github.com/thomascountz)
- Megan Talbot / [meganft](https://github.com/meganft)
- Arun Kumar / [arun1595](https://github.com/arun1595)
- Harry Brodsky / [hbrodsk1](https://github.com/hbrodsk1)
- Jeff Kingswood / [ancyentmariner](https://github.com/ancyentmariner)
- Logan Gingerich / [logangingerich](https://github.com/logangingerich)
## Bots
- Security and Dependency Updates / [deppbot](https://github.com/deppbot)

4
Capfile Normal file
View File

@@ -0,0 +1,4 @@
load 'deploy'
# Uncomment if you are using Rails' asset pipeline
# load 'deploy/assets'
load 'config/deploy' # remove this line to skip loading any of the default tasks

234
Gemfile
View File

@@ -1,160 +1,134 @@
# frozen_string_literal: true
source 'https://rubygems.org'
ruby '2.4.1'
gem 'rails', '~> 4.2.8'
ruby "2.1.5"
gem 'bundler', '>=1.1.5'
gem 'coffee-rails'
gem 'rails', '3.2.13'
gem 'rack', '~>1.4.5'
gem 'json', '~>1.7.7'
gem 'haml'
gem 'sass-rails'
# API data
gem 'jsonapi-resources'
# CSS framework
gem 'bootstrap-sass'
gem 'font-awesome-sass'
gem 'uglifier' # JavaScript compressor
# planting and harvest predictions
gem 'active_median'
gem 'flickraw'
gem 'jquery-rails'
gem 'jquery-ui-rails', '~> 5.0.2' # needs careful upgrade with change of location
gem 'js-routes' # provides access to Rails routes in Javascript
gem 'cancancan' # for checking member privileges
gem 'csv_shaper' # CSV export
gem 'figaro' # for handling config via ENV variables
gem 'gibbon', '~>1.2.0' # for Mailchimp newsletter subscriptions
# Maps
gem 'leaflet-rails'
gem 'rails-assets-leaflet.markercluster', source: 'https://rails-assets.org'
gem 'leaflet-markercluster-rails'
gem 'unicorn' # http server
gem 'pg'
gem 'ruby-units' # for unit conversion
gem 'unicorn' # http server
gem 'comfortable_mexican_sofa' # content management system
gem 'figaro' # for handling config via ENV variables
gem 'bootstrap-kaminari-views' # bootstrap views for kaminari
gem 'kaminari' # pagination
gem 'cancan' # for checking member privileges
gem 'active_utils'
gem 'activemerchant'
gem 'sidekiq'
gem 'gibbon' # for Mailchimp newsletter subscriptions
# Markdown formatting for updates etc
gem 'bluecloth'
gem 'csv_shaper' # CSV export
# Pagination
gem 'will_paginate'
# user signup/login/etc
gem 'devise'
# nicely formatted URLs
gem 'friendly_id'
# gravatars
gem 'gravatar-ultimate'
# For geolocation
gem 'geocoder'
# For easy calendar selection
gem 'bootstrap-datepicker-rails'
# For connecting to other services (eg Twitter)
gem 'omniauth', '~> 1.3'
gem 'omniauth-facebook'
gem 'omniauth-flickr', '>= 0.0.15'
gem 'omniauth-twitter'
# For charting data
gem 'd3-rails', '~> 3.5' # 4.* produces Error: <spyOn> : could not find an object to spy upon for linear() - see https://travis-ci.org/Growstuff/growstuff/jobs/204461482
# 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.
# Project does not use semver, so we want to be in sync with the version of
# elasticsearch we use
# See https://github.com/elastic/elasticsearch-ruby#compatibility
gem "elasticsearch-api", "~> 2.0.0"
gem "elasticsearch-model"
gem "elasticsearch-rails"
gem "hashie", ">= 3.5.3"
gem 'rake', '>= 10.0.0'
# locale based flash notices for controllers
gem "responders"
# allows soft delete. Used for members.
gem 'acts_as_paranoid', '~> 0.5.0'
gem 'xmlrpc' # fixes rake error - can be removed if not needed later
# vendored activemerchant for testing- needed for bogus paypal
# gateway monkeypatch
gem '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'
group :production, :staging do
gem 'bonsai-elasticsearch-rails' # Integration with Bonsa-Elasticsearch on heroku
gem 'newrelic_rpm'
gem 'dalli'
gem 'memcachier'
gem 'newrelic_rpm'
gem 'rails_12factor' # supresses heroku plugin injection
gem 'sparkpost_rails'
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 'better_errors', '~> 2.2.0'
gem 'binding_of_caller'
gem 'guard'
gem 'guard-rspec'
gem 'letter_opener'
gem 'pry'
gem 'quiet_assets'
gem 'better_errors'
gem 'binding_of_caller'
gem 'letter_opener'
end
# Markdown formatting for updates etc
gem 'bluecloth'
# Pagination
gem 'will_paginate', '~> 3.0'
# user signup/login/etc
gem 'devise', '~> 3.2.0'
# nicely formatted URLs
gem 'friendly_id', '~> 4.0.10'
# gravatars
gem 'gravatar-ultimate'
# For geolocation
gem 'geocoder',
:git => 'https://github.com/alexreisner/geocoder.git',
:ref => '104d46'
# For easy calendar selection
gem 'bootstrap-datepicker-rails'
# For connecting to other services (eg Twitter)
gem 'omniauth'
gem 'omniauth-twitter'
gem 'omniauth-flickr', '>= 0.0.15'
gem 'rake', '>= 10.0.0'
group :development, :test do
gem "active_merchant-paypal-bogus-gateway"
gem 'bullet' # performance tuning by finding unnecesary queries
gem 'byebug' # debugging
gem 'capybara' # integration tests
gem 'capybara-email' # integration tests for email
gem 'capybara-screenshot' # for test debugging
gem 'coveralls', require: false # coverage analysis
gem 'database_cleaner'
gem 'factory_bot_rails' # for creating test data
gem 'faker'
gem 'haml-i18n-extractor'
gem 'haml-rails' # HTML templating language
gem 'haml_lint' # Checks haml files for goodness
gem 'i18n-tasks' # adds tests for finding missing and unused translations
gem 'jasmine' # javascript unit testing
gem 'poltergeist' # for headless JS testing
gem 'rainbow', '< 2.2.0' # See https://github.com/sickill/rainbow/issues/44
gem 'rspec-activemodel-mocks'
gem 'rspec-rails' # unit testing framework
gem 'rubocop'
gem 'selenium-webdriver'
gem 'webrat' # provides HTML matchers for view tests
end
group :test do
gem 'codeclimate-test-reporter', require: false
gem 'timecop'
end
group :travis do
gem 'platform-api'
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 'json_spec' # extra ways to test JSON data
end

View File

@@ -1,646 +1,394 @@
GIT
remote: https://github.com/alexreisner/geocoder.git
revision: 104d466ba7097b7dce5ba19f8e4091b7f69ccdf6
ref: 104d46
specs:
geocoder (1.1.8)
PATH
remote: vendor/gems/active_utils-1.0.5
specs:
active_utils (1.0.5)
activesupport (>= 2.3.11)
i18n
PATH
remote: vendor/gems/activemerchant-1.33.0
specs:
activemerchant (1.33.0)
GEM
remote: https://rubygems.org/
remote: https://rails-assets.org/
specs:
actionmailer (4.2.10)
actionpack (= 4.2.10)
actionview (= 4.2.10)
activejob (= 4.2.10)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5)
actionpack (4.2.10)
actionview (= 4.2.10)
activesupport (= 4.2.10)
rack (~> 1.6)
rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (4.2.10)
activesupport (= 4.2.10)
builder (~> 3.1)
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)
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
active_link_to (1.0.5)
actionpack
addressable
active_median (0.1.4)
activerecord
active_merchant-paypal-bogus-gateway (0.1.0)
activemerchant
active_utils (3.3.9)
activesupport (>= 3.2, < 5.2.0)
i18n
activejob (4.2.10)
activesupport (= 4.2.10)
globalid (>= 0.3.0)
activemerchant (1.75.0)
activesupport (>= 3.2.14, < 6.x)
builder (>= 2.1.2, < 4.0.0)
i18n (>= 0.6.9)
nokogiri (~> 1.4)
activemodel (4.2.10)
activesupport (= 4.2.10)
builder (~> 3.1)
activerecord (4.2.10)
activemodel (= 4.2.10)
activesupport (= 4.2.10)
arel (~> 6.0)
activesupport (4.2.10)
i18n (~> 0.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
acts_as_paranoid (0.5.0)
activerecord (>= 4.0, < 5.1)
activesupport (>= 4.0, < 5.1)
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
arel (6.0.4)
ast (2.3.0)
autoprefixer-rails (7.2.3)
execjs
bcrypt (3.1.11)
better_errors (2.2.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)
addressable (2.3.6)
arel (3.0.3)
bcrypt (3.1.9)
better_errors (2.0.0)
coderay (>= 1.0.0)
erubis (>= 2.6.6)
rack (>= 0.9.0)
binding_of_caller (0.7.3)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
bluecloth (2.2.0)
bonsai-elasticsearch-rails (0.2.0)
elasticsearch-model (~> 0)
elasticsearch-rails (~> 0)
bootstrap-datepicker-rails (1.7.1.1)
bootstrap-datepicker-rails (1.3.0.2)
railties (>= 3.0)
bootstrap-kaminari-views (0.0.5)
kaminari (>= 0.13)
rails (>= 3.1)
bootstrap-sass (3.3.7)
autoprefixer-rails (>= 5.2.1)
sass (>= 3.3.4)
bootstrap_form (2.7.0)
builder (3.2.3)
bullet (5.7.0)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.10.0)
byebug (9.1.0)
cancancan (2.1.2)
capybara (2.16.1)
addressable
mini_mime (>= 0.1.3)
builder (3.0.4)
byebug (3.5.1)
columnize (~> 0.8)
debugger-linecache (~> 1.2)
slop (~> 3.6)
cancan (1.6.10)
capybara (2.4.4)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
capybara-email (2.5.0)
capybara-email (2.4.0)
capybara (~> 2.4)
mail
capybara-screenshot (1.0.18)
capybara (>= 1.0, < 3)
launchy
childprocess (0.8.0)
ffi (~> 1.0, >= 1.0.11)
climate_control (0.2.0)
chunky_png (1.3.3)
cliver (0.3.2)
cocaine (0.5.8)
climate_control (>= 0.0.3, < 1.0)
codeclimate-test-reporter (1.0.8)
simplecov (<= 0.13)
codemirror-rails (5.16.0)
railties (>= 3.0, < 6.0)
coderay (1.1.2)
coffee-rails (4.2.2)
coderay (1.1.0)
coffee-rails (3.2.2)
coffee-script (>= 2.2.0)
railties (>= 4.0.0)
coffee-script (2.4.1)
railties (~> 3.2.0)
coffee-script (2.3.0)
coffee-script-source
execjs
coffee-script-source (1.12.2)
comfortable_mexican_sofa (1.12.10)
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.1)
rails-i18n (>= 4.0.0)
sass-rails (>= 4.0.3)
concurrent-ruby (1.0.5)
connection_pool (2.2.1)
coveralls (0.8.19)
json (>= 1.8, < 3)
simplecov (~> 0.12.0)
term-ansicolor (~> 1.3)
thor (~> 0.19.1)
tins (~> 1.6)
crass (1.0.3)
csv_shaper (1.3.0)
coffee-script-source (1.8.0)
columnize (0.8.9)
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
simplecov (>= 0.7)
term-ansicolor
thor
csv_shaper (1.1.1)
activesupport (>= 3.0.0)
d3-rails (3.5.17)
railties (>= 3.1)
dalli (2.7.6)
database_cleaner (1.6.2)
debug_inspector (0.0.3)
devise (4.3.0)
dalli (2.7.2)
database_cleaner (1.3.0)
debug_inspector (0.0.2)
debugger-linecache (1.2.0)
devise (3.2.4)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0, < 5.2)
responders
railties (>= 3.2.6, < 5)
thread_safe (~> 0.1)
warden (~> 1.2.3)
diff-lcs (1.3)
diff-lcs (1.1.3)
docile (1.1.5)
easy_translate (0.5.0)
json
thread
thread_safe
elasticsearch (2.0.2)
elasticsearch-api (= 2.0.2)
elasticsearch-transport (= 2.0.2)
elasticsearch-api (2.0.2)
multi_json
elasticsearch-model (0.1.9)
activesupport (> 3)
elasticsearch (> 0.4)
hashie
elasticsearch-rails (0.1.9)
elasticsearch-transport (2.0.2)
faraday
multi_json
erubis (2.7.0)
excon (0.60.0)
execjs (2.7.0)
factory_bot (4.8.2)
execjs (2.2.2)
factory_girl (4.5.0)
activesupport (>= 3.0.0)
factory_bot_rails (4.8.2)
factory_bot (~> 4.8.2)
factory_girl_rails (4.5.0)
factory_girl (~> 4.5.0)
railties (>= 3.0.0)
faker (1.8.5)
i18n (~> 0.9.1)
faraday (0.12.2)
multipart-post (>= 1.2, < 3)
ffi (1.9.18)
figaro (1.1.1)
figaro (1.0.0)
thor (~> 0.14)
flickraw (0.9.9)
font-awesome-sass (4.7.0)
sass (>= 3.2)
formatador (0.2.5)
friendly_id (5.2.3)
activerecord (>= 4.0.0)
geocoder (1.4.5)
gibbon (1.2.1)
flickraw (0.9.8)
friendly_id (4.0.10.1)
activerecord (>= 3.0, < 4.0)
fssm (0.2.10)
gibbon (1.1.4)
httparty
multi_json (>= 1.9.0)
globalid (0.4.1)
activesupport (>= 4.2.0)
multi_json (>= 1.3.4)
gravatar-ultimate (2.0.0)
activesupport (>= 2.3.14)
rack
guard (2.14.1)
formatador (>= 0.2.4)
listen (>= 2.7, < 4.0)
lumberjack (~> 1.0)
nenv (~> 0.1)
notiffany (~> 0.0)
pry (>= 0.9.12)
shellany (~> 0.0)
thor (>= 0.18.1)
guard-compat (1.2.1)
guard-rspec (4.7.3)
guard (~> 2.1)
guard-compat (~> 1.1)
rspec (>= 2.99.0, < 4.0)
haml (5.0.4)
temple (>= 0.8.0)
haml (4.0.5)
tilt
haml-i18n-extractor (0.5.9)
activesupport
haml
highline
tilt
trollop (= 1.16.2)
haml-rails (1.0.0)
actionpack (>= 4.0.1)
activesupport (>= 4.0.1)
haml (>= 4.0.6, < 6.0)
html2haml (>= 1.0.1)
railties (>= 4.0.1)
haml_lint (0.26.0)
haml (>= 4.0, < 5.1)
rainbow
rake (>= 10, < 13)
rubocop (>= 0.49.0)
sysexits (~> 1.1)
hashie (3.5.6)
heroics (0.0.24)
erubis (~> 2.0)
excon
moneta
multi_json (>= 1.9.2)
highline (1.7.10)
html2haml (2.2.0)
erubis (~> 2.7.0)
haml (>= 4.0, < 6)
nokogiri (>= 1.6.0)
ruby_parser (~> 3.5)
httparty (0.15.6)
haml-rails (0.4)
actionpack (>= 3.1, < 4.1)
activesupport (>= 3.1, < 4.1)
haml (>= 3.1, < 4.1)
railties (>= 3.1, < 4.1)
hashie (3.3.2)
highline (1.6.21)
hike (1.2.3)
httparty (0.11.0)
multi_json (~> 1.0)
multi_xml (>= 0.5.2)
i18n (0.9.1)
concurrent-ruby (~> 1.0)
i18n-tasks (0.9.12)
activesupport (>= 4.0.2)
ast (>= 2.1.0)
i18n (0.6.1)
i18n-tasks (0.7.8)
activesupport
easy_translate (>= 0.5.0)
erubis
highline (>= 1.7.3)
highline
i18n
parser (>= 2.2.3.0)
term-ansicolor (>= 1.3.2)
terminal-table (>= 1.5.1)
jasmine (2.8.0)
jasmine-core (>= 2.8.0, < 3.0.0)
phantomjs
rack (>= 1.2.1)
rake
jasmine-core (2.8.0)
jquery-rails (4.3.1)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
slop (>= 3.5.0)
term-ansicolor
terminal-table
jbuilder (2.2.6)
activesupport (>= 3.0.0, < 5)
multi_json (~> 1.2)
journey (1.0.4)
jquery-rails (3.1.2)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
jquery-ui-rails (5.0.5)
railties (>= 3.2.16)
js-routes (1.4.2)
jquery-ui-rails (4.1.2)
railties (>= 3.1.0)
js-routes (0.9.9)
railties (>= 3.2)
sprockets-rails
json (2.1.0)
jsonapi-resources (0.9.0)
activerecord (>= 4.1)
concurrent-ruby
railties (>= 4.1)
jwt (1.5.6)
kaminari (1.1.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.1.1)
kaminari-activerecord (= 1.1.1)
kaminari-core (= 1.1.1)
kaminari-actionview (1.1.1)
actionview
kaminari-core (= 1.1.1)
kaminari-activerecord (1.1.1)
activerecord
kaminari-core (= 1.1.1)
kaminari-core (1.1.1)
kgio (2.11.1)
kramdown (1.16.2)
json (1.7.7)
json_spec (1.1.4)
multi_json (~> 1.0)
rspec (>= 2.0, < 4.0)
kgio (2.9.2)
launchy (2.4.3)
addressable (~> 2.3)
leaflet-rails (1.2.0)
rails (>= 4.2.0)
letter_opener (1.4.1)
leaflet-markercluster-rails (0.7.0)
railties (>= 3.1)
leaflet-rails (0.7.4)
less (2.5.1)
commonjs (~> 0.2.7)
less-rails (2.5.0)
actionpack (>= 3.1)
less (~> 2.5.0)
less-rails-bootstrap (3.2.0)
less-rails (~> 2.5.0)
letter_opener (1.2.0)
launchy (~> 2.2)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2)
loofah (2.1.1)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
lumberjack (1.0.12)
mail (2.7.0)
mini_mime (>= 0.1.1)
libv8 (3.16.14.7)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
memcachier (0.0.2)
method_source (0.9.0)
mime-types (3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mimemagic (0.3.2)
mini_mime (1.0.0)
mini_portile2 (2.3.0)
minitest (5.10.3)
moneta (0.8.1)
multi_json (1.11.3)
multi_xml (0.6.0)
multipart-post (2.0.0)
nenv (0.3.0)
newrelic_rpm (4.6.0.338)
nokogiri (1.8.1)
mini_portile2 (~> 2.3.0)
notiffany (0.1.1)
nenv (~> 0.1)
shellany (~> 0.0)
oauth (0.5.4)
oauth2 (1.4.0)
faraday (>= 0.8, < 0.13)
jwt (~> 1.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
omniauth (1.7.1)
hashie (>= 3.4.6, < 3.6.0)
rack (>= 1.6.2, < 3)
omniauth-facebook (4.0.0)
omniauth-oauth2 (~> 1.2)
omniauth-flickr (0.0.19)
multi_json (~> 1.11.0)
method_source (0.8.2)
mime-types (1.25.1)
mini_portile (0.6.1)
multi_json (1.10.1)
multi_xml (0.5.5)
netrc (0.8.0)
newrelic_rpm (3.9.7.266)
nokogiri (1.6.5)
mini_portile (~> 0.6.0)
oauth (0.4.7)
omniauth (1.2.2)
hashie (>= 1.2, < 4)
rack (~> 1.0)
omniauth-flickr (0.0.15)
omniauth-oauth (~> 1.0)
omniauth-oauth (1.1.0)
omniauth-oauth (1.0.1)
oauth
omniauth (~> 1.0)
omniauth-oauth2 (1.5.0)
oauth2 (~> 1.1)
omniauth (~> 1.2)
omniauth-twitter (1.4.0)
omniauth-oauth (~> 1.1)
rack
omniauth-twitter (1.1.0)
multi_json (~> 1.3)
omniauth-oauth (~> 1.0)
orm_adapter (0.5.0)
paperclip (5.1.0)
activemodel (>= 4.2.0)
activesupport (>= 4.2.0)
cocaine (~> 0.5.5)
mime-types
mimemagic (~> 0.3.0)
parallel (1.12.1)
parser (2.4.0.2)
ast (~> 2.3)
pg (0.21.0)
phantomjs (2.1.1.0)
platform-api (2.1.0)
heroics (~> 0.0.23)
moneta (~> 0.8.1)
plupload-rails (1.2.1)
rails (>= 3.1)
poltergeist (1.17.0)
pg (0.17.1)
poltergeist (1.5.1)
capybara (~> 2.1)
cliver (~> 0.3.1)
multi_json (~> 1.0)
websocket-driver (>= 0.2.0)
powerpack (0.1.1)
pry (0.11.3)
polyglot (0.3.5)
pry (0.10.1)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
public_suffix (3.0.1)
quiet_assets (1.1.0)
railties (>= 3.1, < 5.0)
rack (1.6.8)
rack-protection (2.0.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.3)
rack-test (0.6.2)
rack (>= 1.0)
rails (4.2.10)
actionmailer (= 4.2.10)
actionpack (= 4.2.10)
actionview (= 4.2.10)
activejob (= 4.2.10)
activemodel (= 4.2.10)
activerecord (= 4.2.10)
activesupport (= 4.2.10)
bundler (>= 1.3.0, < 2.0)
railties (= 4.2.10)
sprockets-rails
rails-assets-leaflet (1.2.0)
rails-assets-leaflet.markercluster (1.2.0)
rails-assets-leaflet (>= 1.0.3)
rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha)
rails-dom-testing (1.0.8)
activesupport (>= 4.2.0.beta, < 5.0)
nokogiri (~> 1.6)
rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
rails-i18n (4.0.9)
i18n (~> 0.7)
railties (~> 4.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_12factor (0.0.3)
rails_serve_static_assets
rails_stdout_logging
rails_serve_static_assets (0.0.5)
rails_stdout_logging (0.0.5)
railties (4.2.10)
actionpack (= 4.2.10)
activesupport (= 4.2.10)
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)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (2.1.0)
raindrops (0.19.0)
rake (12.3.0)
rb-fsevent (0.10.2)
rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2)
redis (4.0.1)
responders (2.4.0)
actionpack (>= 4.2.0, < 5.3)
railties (>= 4.2.0, < 5.3)
rspec (3.7.0)
rspec-core (~> 3.7.0)
rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.7.0)
rspec-activemodel-mocks (1.0.3)
activemodel (>= 3.0)
activesupport (>= 3.0)
rspec-mocks (>= 2.99, < 4.0)
rspec-core (3.7.0)
rspec-support (~> 3.7.0)
rspec-expectations (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0)
rspec-mocks (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0)
rspec-rails (3.7.2)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
raindrops (0.13.0)
rake (10.4.0)
rdoc (3.12.2)
json (~> 1.4)
ref (1.0.5)
rest-client (1.7.2)
mime-types (>= 1.16, < 3.0)
netrc (~> 0.7)
rspec (2.12.0)
rspec-core (~> 2.12.0)
rspec-expectations (~> 2.12.0)
rspec-mocks (~> 2.12.0)
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)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 3.7.0)
rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.7.0)
rspec-support (~> 3.7.0)
rspec-support (3.7.0)
rubocop (0.49.1)
parallel (~> 1.10)
parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-progressbar (1.9.0)
ruby-units (2.2.1)
ruby_dep (1.5.0)
ruby_parser (3.10.1)
sexp_processor (~> 4.9)
rubyzip (1.2.1)
sass (3.5.4)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
sass-rails (5.0.7)
railties (>= 4.0.0, < 6)
sass (~> 3.1)
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
selenium-webdriver (3.8.0)
childprocess (~> 0.5)
rubyzip (~> 1.0)
sexp_processor (4.10.0)
shellany (0.0.1)
sidekiq (5.0.5)
concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0)
rack-protection (>= 1.5.0)
redis (>= 3.3.4, < 5)
simplecov (0.12.0)
rspec-core (~> 2.12.0)
rspec-expectations (~> 2.12.0)
rspec-mocks (~> 2.12.0)
sass (3.2.19)
sass-rails (3.2.6)
railties (~> 3.2.0)
sass (>= 3.1.10)
tilt (~> 1.3)
simplecov (0.9.1)
docile (~> 1.1.0)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
sparkpost_rails (1.5.0)
rails (>= 4.0, < 5.2)
sprockets (3.7.1)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sysexits (1.2.0)
temple (0.8.0)
term-ansicolor (1.6.0)
multi_json (~> 1.0)
simplecov-html (~> 0.8.0)
simplecov-html (0.8.0)
slop (3.6.0)
sprockets (2.2.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)
term-ansicolor (1.3.0)
tins (~> 1.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
thor (0.19.4)
thread (0.2.2)
thread_safe (0.3.6)
tilt (2.0.8)
timecop (0.9.1)
tins (1.16.3)
trollop (1.16.2)
tzinfo (1.2.4)
thread_safe (~> 0.1)
uglifier (4.0.2)
execjs (>= 0.3.0, < 3)
unicode-display_width (1.3.0)
unicorn (5.3.1)
terminal-table (1.4.5)
therubyracer (0.12.1)
libv8 (~> 3.16.14.0)
ref
thor (0.19.1)
thread (0.1.4)
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)
execjs (>= 0.3.0)
multi_json (~> 1.0, >= 1.0.2)
unicorn (4.8.3)
kgio (~> 2.6)
rack
raindrops (~> 0.7)
uniform_notifier (1.10.0)
warden (1.2.7)
warden (1.2.3)
rack (>= 1.0)
webrat (0.7.3)
nokogiri (>= 1.2.0)
rack (>= 1.0)
rack-test (>= 0.5.3)
websocket-driver (0.7.0)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.3)
will_paginate (3.1.6)
xmlrpc (0.3.0)
xpath (2.1.0)
websocket-driver (0.4.0)
will_paginate (3.0.7)
xpath (2.0.0)
nokogiri (~> 1.3)
PLATFORMS
ruby
DEPENDENCIES
active_median
active_merchant-paypal-bogus-gateway
active_utils
activemerchant
acts_as_paranoid (~> 0.5.0)
better_errors (~> 2.2.0)
active_utils (= 1.0.5)!
activemerchant (= 1.33.0)!
better_errors
binding_of_caller
bluecloth
bonsai-elasticsearch-rails
bootstrap-datepicker-rails
bootstrap-kaminari-views
bootstrap-sass
bullet
bundler (>= 1.1.5)
byebug
cancancan
cancan
capybara
capybara-email
capybara-screenshot
codeclimate-test-reporter
coffee-rails
comfortable_mexican_sofa
coffee-rails (~> 3.2.1)
compass-rails (~> 1.0.3)
coveralls
csv_shaper
d3-rails (~> 3.5)
dalli
database_cleaner
devise
elasticsearch-api (~> 2.0.0)
elasticsearch-model
elasticsearch-rails
factory_bot_rails
faker
database_cleaner (~> 1.3.0)
devise (~> 3.2.0)
factory_girl_rails (~> 4.0)
figaro
flickraw
font-awesome-sass
friendly_id
geocoder
gibbon (~> 1.2.0)
friendly_id (~> 4.0.10)
geocoder!
gibbon
gravatar-ultimate
guard
guard-rspec
haml
haml-i18n-extractor
haml-rails
haml_lint
hashie (>= 3.5.3)
i18n-tasks
jasmine
jbuilder
jquery-rails
jquery-ui-rails (~> 5.0.2)
jquery-ui-rails
js-routes
jsonapi-resources
kaminari
json (~> 1.7.7)
json_spec
leaflet-markercluster-rails
leaflet-rails
less (~> 2.5.0)
less-rails (~> 2.5.0)
less-rails-bootstrap (~> 3.2.0)
letter_opener
libv8 (= 3.16.14.7)
memcachier
newrelic_rpm
omniauth (~> 1.3)
omniauth-facebook
omniauth
omniauth-flickr (>= 0.0.15)
omniauth-twitter
pg
platform-api
poltergeist
poltergeist (~> 1.5.1)
pry
quiet_assets
rails (~> 4.2.8)
rails-assets-leaflet.markercluster!
rack (~> 1.4.5)
rails (= 3.2.13)
rails_12factor
rainbow (< 2.2.0)
rake (>= 10.0.0)
responders
rspec-activemodel-mocks
rspec-rails
rubocop
ruby-units
sass-rails
selenium-webdriver
sidekiq
sparkpost_rails
timecop
uglifier
rspec-rails (~> 2.12.1)
sass-rails (~> 3.2.3)
therubyracer (~> 0.12)
uglifier (>= 1.0.3)
unicorn
webrat
will_paginate
xmlrpc
RUBY VERSION
ruby 2.4.1p111
BUNDLED WITH
1.16.0
will_paginate (~> 3.0)

View File

@@ -1,13 +0,0 @@
guard :rspec,
cmd: 'bundle exec rspec --format documentation',
failed_mode: :keep do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/libs/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }
# Rails example
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
watch('config/routes.rb') { "spec/routing" }
end

View File

@@ -1,8 +1,7 @@
# Growstuff
[![Build Status](https://travis-ci.org/Growstuff/growstuff.svg?branch=dev)](https://travis-ci.org/Growstuff/growstuff)
[![Build Status](https://travis-ci.org/Growstuff/growstuff.png)](https://travis-ci.org/Growstuff/growstuff)
[![Coverage Status](https://coveralls.io/repos/Growstuff/growstuff/badge.png)](https://coveralls.io/r/Growstuff/growstuff)
[![Code Climate](https://codeclimate.com/github/Growstuff/growstuff/badges/gpa.svg)](https://codeclimate.com/github/Growstuff/growstuff)
Welcome to the Growstuff project.
@@ -19,8 +18,8 @@ encourage participation from people of all backgrounds and skill levels.
* [Issues](http://github.com/Growstuff/growstuff/issues) (features we're
working on, known bugs, etc)
* [IRC](https://webchat.freenode.net/) growstuff channel (general chat, brainstorming and troubleshooting) or [Gitter](https://gitter.im/Growstuff/growstuff)
* [Wiki](https://github.com/Growstuff/growstuff/wiki) (general documentation, etc. Help by migrating from the [old wiki](https://web.archive.org/web/*/wiki.growstuff.org))
* [Discussion forums](http://wiki.growstuff.org/index.php/Discussion_forums) (mailing lists, IRC, etc)
* [Wiki](http://wiki.growstuff.org/) (general documentation)
## For coders
@@ -28,9 +27,10 @@ Growstuff is built in Ruby on Rails and also uses JavaScript for
frontend features. We welcome contributions -- see
[CONTRIBUTING](CONTRIBUTING.md) for details.
* To set up your development environment, see [Getting started](https://github.com/Growstuff/growstuff/wiki/New-contributor-guide).
* We encourage [pair programming](http://wiki.growstuff.org/index.php/Pairing), especially for newer developers.
* You may also be interested in our [API](https://github.com/Growstuff/growstuff/wiki/API).
* 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. [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
@@ -39,25 +39,22 @@ your skills and interests.
You might like to check out:
* The [New Contributor Guide](https://github.com/Growstuff/growstuff/wiki/New-contributor-guide)
* 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:
* [Waffle](http://waffle.io/Growstuff/growstuff) has stories in "ready" that can be worked on.
* [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
* [curated:beginner](https://github.com/Growstuff/growstuff/labels/curated:%20beginner) - tasks that are ideal for beginner programmers or people new to the project
Feel free to comment on any of the issues on [Github](https://github.com/Growstuff/growstuff/issues).
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).
Security Issues: If you find an authorization bypass or data breach, please contact our maintainers directly at [maintainers@growstuff.org](mailto:maintainers@growstuff.org).
You can also contact us on [Twitter](http://twitter.com/growstufforg/) or
[Facebook](https://www.facebook.com/pages/Growstuff/1531133417099494) or [Github](https://github.com/Growstuff/growstuff/issues)..
[Facebook](https://www.facebook.com/pages/Growstuff/1531133417099494).

0
Rakefile Executable file → Normal file
View File

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 613 B

After

Width:  |  Height:  |  Size: 572 B

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -5,15 +5,17 @@
jQuery ->
el = $('.append-date')
el.datepicker({'format': 'yyyy-mm-dd'})
href = el.attr('href')
originalText = el.text()
el.click (e) ->
e.stopPropagation()
e.preventDefault()
originalText = $(this).text()
href = $(this).attr('href')
$(this).text('Confirm without date')
$(this).bind('click.confirm', (e) ->
@@ -29,8 +31,6 @@ jQuery ->
el.one 'changeDate', ->
date = $(this).datepicker('getDate')
href = $(this).attr('href')
url = "#{href}&planting[finished_at]=#{date}"
link = $("<a href='#{url}' data-method='put'></a>")

View File

@@ -15,7 +15,8 @@
//= require js-routes
//= require jquery
//= require jquery_ujs
//= require jquery-ui/autocomplete
//= require bootstrap-sprockets
//= require bootstrap-datepicker
//= require jquery.ui.autocomplete
//= require twitter/bootstrap
//= require_tree .
//= require bootstrap-datepicker

View File

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
# Custom JS for the admin area

View File

@@ -1,9 +1,6 @@
//= require graphs/horizontal_bar_graph
if (document.getElementById("cropmap") !== null) {
mapbox_map_id = "<%= Rails.env == 'test' ? 0 : Growstuff::Application.config.mapbox_map_id %>";
mapbox_access_token = "<%= Rails.env == 'test' ? 0 : Growstuff::Application.config.mapbox_access_token %>";
mapbox_base_url = "http://a.tiles.mapbox.com/v4/" + mapbox_map_id + "/{z}/{x}/{y}.png?access_token=" + mapbox_access_token;
mapbox_base_url = "https://c.tiles.mapbox.com/v3/" + mapbox_map_id + "/{z}/{x}/{y}.png";
L.Icon.Default.imagePath = '/assets'
@@ -50,42 +47,3 @@ function showCropMap(cropmap) {
cropmap.addLayer(markers);
}
function plantingStats(crop) {
var sunniness_counts = { 'empty': 0, 'sun': 0, 'semi-shade': 0, 'shade': 0 };
$.each(crop.plantings, function(i, planting) {
if (planting.sunniness) {
sunniness_counts[planting.sunniness]++;
} else {
sunniness_counts['Empty']++;
}
});
return [
{name: 'Empty', value: sunniness_counts['empty']},
{name: 'Sun', value: sunniness_counts['sun']},
{name: 'Semi-shade', value: sunniness_counts['semi-shade']},
{name: 'Shade', value: sunniness_counts['shade']}
];
}
if ($("#sunchart")[0] !== null) {
var HorizontalBarGraph = growstuff.HorizontalBarGraph;
$.getJSON(location.pathname + '.json', function (crop) {
data = {
bars: plantingStats(crop),
bar_color: 'steelblue',
width: {size: 300, scale: 'linear'},
height: {size: 100, scale: 'ordinal'},
//left is used to shift the bars over so that there is
//room for the labels
margin: {top: 0, right: 0, bottom: 0, left: 100}
};
var graph = new HorizontalBarGraph(data);
graph.render(d3.select($('#sunchart')[0]));
});
}
$('.btn.toggle.crop-hierarchy').click(function () {
$('.toggle.crop-hierarchy').toggleClass('hide');
});

View File

@@ -9,11 +9,11 @@ jQuery ->
finished = $('#planting_finished_at')
if @checked
if previousValue.length
date = previousValue
date = previousValue
finished.val(date)
else
finished.trigger('focus')
else
previousValue = finished.val()
finished.val('')
)
)

View File

@@ -1,50 +0,0 @@
//= require graphs/width_scale
//= require graphs/height_scale
(function(){
'use strict';
/*
This represents bars for a bar graph.
Currently these are used for HorizontalBarGraph.
*/
var growstuff = (window.growstuff = window.growstuff || {});
var WidthScale = growstuff.WidthScale;
var HeightScale = growstuff.HeightScale;
function BarGroup(data) {
this._data = data;
}
BarGroup.prototype.render = function(root){
var data = this._data;
var bars = this._data.bars;
var widthScale = new WidthScale(data).render();
var heightScale = new HeightScale(data).render();
return root.append('g')
.attr("class", "bar")
.selectAll("rect")
.data(bars.map(function(bar) { return bar.value; }))
.enter()
.append("rect")
.attr("y", function(d, i){
return heightScale(i);
})
.attr("height", heightScale.rangeBand())
.attr("fill", data.bar_color)
.attr("width", function(d){
return widthScale(d);
})
.append("title")
.text(function(d){
return 'This value is ' + d + '.';
});
};
growstuff.BarGroup = BarGroup;
}());

View File

@@ -1,40 +0,0 @@
(function() {
'use strict';
/*
This file draws the labels to the left of each bar.
*/
var growstuff = (window.growstuff = window.growstuff || {});
function BarLabelGroup(data) {
this._data = data;
}
BarLabelGroup.prototype.render = function(d3){
var bars = this._data.bars;
//vvcopy pasta from spike vv -- this is a good candidate for refactor
var barHeight = 40;
return d3.append('g')
.attr("class", "bar-label")
.selectAll("text")
.data(bars.map(function(bar){ return bar.name;}))
.enter()
.append("text")
.attr('x', -80)
.attr('y', function(d, i){
//shrink the margin between each label to give them an even spread with
//bars
var barLabelSpread = 2/3;
//move them downward to line up with bars
var barLabelTopEdge = 17;
return i * barHeight * (barLabelSpread) + barLabelTopEdge;
})
.text(function(d){return d;});
};
growstuff.BarLabelGroup = BarLabelGroup;
}());

View File

@@ -1,29 +0,0 @@
//=require d3
/*
Height Scale is used to map the number of bars to the display size of
the svg
*/
(function(){
'use strict';
var growstuff = (window.growstuff = window.growstuff || {});
function HeightScale(data){
this._data = data;
}
HeightScale.prototype.render = function(){
var data = this._data;
var scaleType = data.height.scale;
var axisSize = data.height.size;
return d3.scale[scaleType]()
.domain(d3.range(data.bars.length))
.rangeRoundBands([0, data.height.size], 0.05, 0);
};
growstuff.HeightScale = HeightScale;
}());

View File

@@ -1,51 +0,0 @@
//= require d3
//= require graphs/bar_group
//= require graphs/bar_label_group
/*
Horizontal Bar Graph represents sum total of the graph including all of the parts:
Bars
Bar Labels
The main dimensions of the graph are rendered here.
*/
(function() {
'use strict';
var growstuff = (window.growstuff = window.growstuff || {});
var BarGroup = growstuff.BarGroup;
var BarLabelGroup = growstuff.BarLabelGroup;
function HorizontalBarGraph(data) {
this._data = data;
this._d3 = d3;
}
HorizontalBarGraph.prototype.render = function(root) {
var bars = this._data.bars;
var width = this._data.width;
var height = this._data.height;
var barLabelGroup = new BarLabelGroup(this._data);
var margin = this._data.margin;
var barGroup = new BarGroup(this._data);
var svg = root
.append("svg")
.attr("width", width.size + margin.left + margin.right)
.attr("height", height.size + margin.top + margin.bottom)
.append("g")
.attr("class","bar-graph")
.attr("transform","translate(" + margin.left + "," + margin.top + ")");
barGroup.render(svg);
barLabelGroup.render(svg);
return svg;
};
growstuff.HorizontalBarGraph = HorizontalBarGraph;
}());

View File

@@ -1,33 +0,0 @@
//=require d3
/*
Width scale is used to map the value for the length of each bar
to the display size of the svg
*/
(function(){
'use strict';
var growstuff = (window.growstuff = window.growstuff || {});
function WidthScale (data){
this._data = data;
}
WidthScale.prototype.render = function() {
var data = this._data;
var scaleType = data.width.scale;
var axisSize = data.width.size;
return d3.scale[scaleType]()
.domain([0, this.getMaxValue()])
.range([0, axisSize]);
};
WidthScale.prototype.getMaxValue = function(){
return d3.max(this._data.bars.map(function(bar) { return bar.value; }));
};
growstuff.WidthScale = WidthScale;
}());

View File

@@ -1,7 +1,6 @@
if (document.getElementById("membermap") !== null) {
mapbox_map_id = "<%= Rails.env == 'test' ? 0 : Growstuff::Application.config.mapbox_map_id %>";
mapbox_access_token = "<%= Rails.env == 'test' ? 0 : Growstuff::Application.config.mapbox_access_token %>";
mapbox_base_url = "http://a.tiles.mapbox.com/v4/" + mapbox_map_id + "/{z}/{x}/{y}.png?access_token=" + mapbox_access_token;
mapbox_base_url = "https://c.tiles.mapbox.com/v3/" + mapbox_map_id + "/{z}/{x}/{y}.png";
L.Icon.Default.imagePath = '/assets'

View File

@@ -1,8 +1,7 @@
if (document.getElementById("placesmap") !== null) {
places_base_path = "/places";
mapbox_map_id = "<%= Rails.env == 'test' ? 0 : Growstuff::Application.config.mapbox_map_id %>";
mapbox_access_token = "<%= Rails.env == 'test' ? 0 : Growstuff::Application.config.mapbox_access_token %>";
mapbox_base_url = "http://a.tiles.mapbox.com/v4/" + mapbox_map_id + "/{z}/{x}/{y}.png?access_token=" + mapbox_access_token;
mapbox_base_url = "https://c.tiles.mapbox.com/v3/" + mapbox_map_id + "/{z}/{x}/{y}.png";
nominatim_base_url = 'http://nominatim.openstreetmap.org/search/';
nominatim_user_agent_email = "<%= Rails.env == 'test' ? 0 : Growstuff::Application.config.user_agent_email %>";

View File

@@ -1,18 +0,0 @@
$(document).ready(function () {
$('.post-like').show();
$('.post-like').on('ajax:success', function(event, data) {
var like_control = $('#post-' + data.id + ' .post-like');
$('#post-' + data.id + ' .like-count').text(data.description);
if (data.liked_by_member) {
like_control.data("method", "delete");
like_control.attr("href", data.url);
like_control.text("Unlike");
} else {
like_control.data("method", "post");
like_control.attr("href", '/likes.json?post_id=' + data.id);
like_control.text("Like");
}
});
});

View File

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

View File

@@ -0,0 +1,14 @@
/*
* This is a manifest file that'll automatically include all the stylesheets available in this directory
* 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 bootstrap-datepicker
*= require leaflet
*= require leaflet.markercluster
*= require leaflet.markercluster.default
*= require custom_bootstrap/custom_bootstrap
*= require overrides.css
*= require_tree .
*/

View File

@@ -1,7 +0,0 @@
@import 'jquery-ui/autocomplete'
@import 'bootstrap-datepicker'
@import 'leaflet'
@import 'leaflet.markercluster'
@import 'custom_bootstrap/custom_bootstrap'
@import 'overrides'
@import 'graphs'

View File

@@ -1 +0,0 @@
.btn:focus{outline:dotted 2px #000}div.active:focus{outline:dotted 1px #000}a:focus{outline:dotted 1px #000}.close:hover,.close:focus{outline:dotted 1px #000}.nav>li>a:hover,.nav>li>a:focus{outline:dotted 1px #000}.carousel-inner>.item{position:absolute;top:-999999em;display:block;-moz-transition:ease-in-out 0.6s left;-o-transition:ease-in-out 0.6s left;-webkit-transition:ease-in-out 0.6s left;transition:ease-in-out 0.6s left}.carousel-inner>.active{top:0}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{position:relative}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.alert-success{color:#2d4821}.alert-info{color:#214c62}.alert-warning{color:#6c4a00;background-color:#f9f1c6}.alert-danger{color:#d2322d}.alert-danger:hover{color:#a82824}

View File

@@ -1 +0,0 @@
// custom CSS for admin area

View File

@@ -0,0 +1,56 @@
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!! AUTOMATICALLY GENERATED FILE. DO NOT MODIFY !!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Core variables and mixins
@import "twitter/bootstrap/variables.less";
@import "custom_bootstrap/variables.less"; // Modify this for custom colors, font-sizes, etc
@import "twitter/bootstrap/mixins.less";
@import "custom_bootstrap/mixins.less"; // Modify this for custom mixins
// Reset and dependencies
@import "twitter/bootstrap/normalize.less";
@import "twitter/bootstrap/print.less";
@import "twitter/bootstrap/glyphicons.less";
// Core CSS
@import "twitter/bootstrap/scaffolding.less";
@import "twitter/bootstrap/type.less";
@import "twitter/bootstrap/code.less";
@import "twitter/bootstrap/grid.less";
@import "twitter/bootstrap/tables.less";
@import "twitter/bootstrap/forms.less";
@import "twitter/bootstrap/buttons.less";
// Components
@import "twitter/bootstrap/component-animations.less";
@import "twitter/bootstrap/dropdowns.less";
@import "twitter/bootstrap/button-groups.less";
@import "twitter/bootstrap/input-groups.less";
@import "twitter/bootstrap/navs.less";
@import "twitter/bootstrap/navbar.less";
@import "twitter/bootstrap/breadcrumbs.less";
@import "twitter/bootstrap/pagination.less";
@import "twitter/bootstrap/pager.less";
@import "twitter/bootstrap/labels.less";
@import "twitter/bootstrap/badges.less";
@import "twitter/bootstrap/jumbotron.less";
@import "twitter/bootstrap/thumbnails.less";
@import "twitter/bootstrap/alerts.less";
@import "twitter/bootstrap/progress-bars.less";
@import "twitter/bootstrap/media.less";
@import "twitter/bootstrap/list-group.less";
@import "twitter/bootstrap/panels.less";
@import "twitter/bootstrap/responsive-embed.less";
@import "twitter/bootstrap/wells.less";
@import "twitter/bootstrap/close.less";
// Components w/ JavaScript
@import "twitter/bootstrap/modals.less";
@import "twitter/bootstrap/tooltip.less";
@import "twitter/bootstrap/popovers.less";
@import "twitter/bootstrap/carousel.less";
// Utility classes
@import "twitter/bootstrap/utilities.less";
@import "twitter/bootstrap/responsive-utilities.less";

View File

@@ -1,59 +0,0 @@
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// !!! AUTOMATICALLY GENERATED FILE. DO NOT MODIFY !!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Core variables and mixins
@import "bootstrap-sprockets"
@import "bootstrap/variables"
// Modify this for custom colors, font-sizes, etc
@import "custom_bootstrap/variables"
@import "bootstrap/mixins"
// Modify this for custom mixins
@import "custom_bootstrap/mixins"
// Reset and dependencies
@import "bootstrap/normalize"
@import "bootstrap/print"
@import "bootstrap/glyphicons"
// Core CSS
@import "bootstrap/scaffolding"
@import "bootstrap/type"
@import "bootstrap/code"
@import "bootstrap/grid"
@import "bootstrap/tables"
@import "bootstrap/forms"
@import "bootstrap/buttons"
// Components
@import "bootstrap/component-animations"
@import "bootstrap/dropdowns"
@import "bootstrap/button-groups"
@import "bootstrap/input-groups"
@import "bootstrap/navs"
@import "bootstrap/navbar"
@import "bootstrap/breadcrumbs"
@import "bootstrap/pagination"
@import "bootstrap/pager"
@import "bootstrap/labels"
@import "bootstrap/badges"
@import "bootstrap/jumbotron"
@import "bootstrap/thumbnails"
@import "bootstrap/alerts"
@import "bootstrap/progress-bars"
@import "bootstrap/media"
@import "bootstrap/list-group"
@import "bootstrap/panels"
@import "bootstrap/responsive-embed"
@import "bootstrap/wells"
@import "bootstrap/close"
// Components w/ JavaScript
@import "bootstrap/modals"
@import "bootstrap/tooltip"
@import "bootstrap/popovers"
@import "bootstrap/carousel"
// Utility classes
@import "bootstrap/utilities"
@import "bootstrap/responsive-utilities"

View File

@@ -0,0 +1,54 @@
// Use this file to override Twitter Bootstrap variables or define own variables.
// Import original variables so they can be used in overrides
@import "twitter/bootstrap/variables.less";
// Base colours
@beige: #f3f1ee;
@brown: #413f3b;
@green: #5f8e43;
@blue: #2f4365;
@red: #8e4d43;
@orange: #b2685c;
@yellow: #b2935c;
@body-bg: @beige;
@text-color: @brown;
@link-color: @green;
@brand-primary: @green;
@font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif;
@font-family-serif: Georgia, "Times New Roman", Times, serif;
@font-family-mono: Monaco, Menlo, Consolas, "Courier New", monospace;
@font-size-base: 14px;
@font-family-base: @font-family-sans-serif;
@line-height-base: 1.5;
@alt-font-family: @font-family-serif;
@headings-font-family: @font-family-sans-serif;
@headings-font-weight: bold; // instead of browser default, bold
@headings-color: inherit; // empty to use BS default, @textColor
// Hero unit
@jumbotron-bg: darken(@body-bg, 10%);
// Nav bar
@navbar-default-bg: @brown;
@navbar-default-bg-highlight: @brown;
@navbar-default-color: @beige;
@navbar-default-link-color: darken(@beige, 20%);
@navbar-default-link-hover-color: @beige;
@navbar-default-link-active-color: @beige;
@navbar-default-brand-color: lighten(@green, 20%);
// Top nav collapse threshold
@grid-float-breakpoint: @screen-md-min;
@dropdown-bg: lighten(@beige, 10%);
@dropdown-link-color: @brown;
@dropdown-link-hover-color: @brown;
@dropdown-link-hover-bg: lighten(@green, 50%);

View File

@@ -1,55 +0,0 @@
// Use this file to override Twitter Bootstrap variables or define own variables.
// Import original variables so they can be used in overrides
//@import 'bootstrap/variables.scss'
// Base colours
$beige: #f3f1ee
$brown: #413f3b
$green: #5f8e43
$blue: #2f4365
$red: #8e4d43
$orange: #ffa500
$yellow: #b2935c
$body-bg: $beige
$text-color: $brown
$link-color: $green
$graph-hover: $orange
$brand-primary: $green
$font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif
$font-family-serif: Georgia, "Times New Roman", Times, serif
$font-family-mono: Monaco, Menlo, Consolas, "Courier New", monospace
$font-size-base: 14px
$font-family-base: $font-family-sans-serif
$line-height-base: 1.5
$alt-font-family: $font-family-serif
$headings-font-family: $font-family-sans-serif
$headings-font-weight: bold // instead of browser default, bold
$headings-color: inherit // empty to use BS default, $textColor
// Hero unit
$jumbotron-bg: darken($body-bg, 10%)
// Nav bar
$navbar-default-bg: $brown
$navbar-default-bg-highlight: $brown
$navbar-default-color: $beige
$navbar-default-link-color: darken($beige, 20%)
$navbar-default-link-hover-color: $beige
$navbar-default-link-active-color: darken($beige,80%)
$navbar-default-brand-color: lighten($green, 20%)
// Top nav collapse threshold
$grid-float-breakpoint: $screen-md-min
$dropdown-bg: lighten($beige, 10%)
$dropdown-link-color: $brown
$dropdown-link-hover-color: $brown
$dropdown-link-hover-bg: lighten($green, 50%)

View File

@@ -1,2 +0,0 @@
.bar rect:hover
fill: $graph-hover

View File

@@ -0,0 +1,3 @@
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
border: none;
}

View File

@@ -1,10 +0,0 @@
.leaflet-popup-content-wrapper,
.leaflet-popup-tip
border: none
.thumbnail
background: #fff !important
border: solid 1px whitesmoke
.thumbnail .crop-thumbnail .cropinfo
padding-top: 14px

View File

@@ -0,0 +1,263 @@
@import "twitter/bootstrap/bootstrap";
@import "custom_bootstrap/variables";
// this padding needs to be done before the responsive stuff is imported
body {
// modifying this for our promotional banner. can be replaced after if
// needed.
// padding-top: @navbar-height + 15px;
padding-top: @navbar-height;
}
//@import "twitter/bootstrap/responsive";
// Set the correct sprite paths
@iconSpritePath: asset-path("twitter/bootstrap/glyphicons-halflings");
@iconWhiteSpritePath: asset-path("twitter/bootstrap/glyphicons-halflings-white");
// Set the Font Awesome (Font Awesome is default. You can disable by commenting below lines)
@fontAwesomeEotPath: asset-url("fontawesome-webfont.eot");
@fontAwesomeEotPath_iefix: asset-url("fontawesome-webfont.eot#iefix");
@fontAwesomeWoffPath: asset-url("fontawesome-webfont.woff");
@fontAwesomeTtfPath: asset-url("fontawesome-webfont.ttf");
@fontAwesomeSvgPath: asset-url("fontawesome-webfont.svg#fontawesomeregular");
// Font Awesome
//@import "fontawesome/font-awesome";
// Glyphicons
//@import "twitter/bootstrap/sprites.less";
.list-inline > li.first {
padding-left: 0px;
}
h2 {
font-size: 150%;
}
/*
#subtitle {
color: lighten(@brown, 30%);
margin-top: 0px;
padding-top: 0px;
padding-left: 1em;
font-style: italic;
font-weight: normal;
}
*/
h3 {
font-size: 120%;
}
.main {
padding-right: 1em;
}
.sidebar {
margin-left: -1px;
border-left: 1px solid darken(@beige, 10%);
padding-left: 1em;
}
// this is used for eg. crops and members index pages
.six-across:nth-child(6n+1) {
margin-left: 0px
}
.three-across:nth-child(3n+1) {
margin-left: 0px;
clear: both;
}
// let's condense the hero unit a little
.jumbotron {
padding-top: 30px;
padding-bottom: 30px;
}
// info under the main heading on homepage
.jumbotron .info {
padding-top: 15px;
}
// signup widget on homepage
.jumbotron .signup {
background-color: lighten(@green, 40%);
border: 1px solid lighten(@green, 20%);
border-radius: 6px;
padding: 15px;
text-align: center;
line-height: 200%;
}
// stats shown on homepage. eg. "999 members..."
p.stats {
font-weight: bold;
}
.homepage-members {
height: 100px;
}
.homepage-members:nth-child(odd) {
margin-left: 0px;
}
#placesmap, #cropmap {
height: 500px;
}
#membermap {
height: 250px;
}
.member-location {
font-size: small;
font-style: italic;
}
.member-location a {
color: @brown;
}
.crop-thumbnail {
position:relative;
padding:0;
img {
width:100%;
}
.text {
display:none;
color:#000;
position:absolute;
bottom:0;
background:rgba(0, 0, 0, 0.8);
width:100%;
margin:0;
}
p {
padding:5px;
margin:0;
color:#fff;
}
&:hover {
.text {
display:block;
}
}
}
.member-thumbnail {
img {
height: 85px;
width: 85px;
max-width: 85px
}
}
.thumbnail {
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;
}
.crop-name a {
padding-top: 2px;
}
.scientific-name small {
margin-bottom: -2px;
}
}
li.crop-hierarchy {
list-style-type: disc;
}
.navbar-brand {
margin: 0px;
padding: 0px;
}
.navbar-bottom {
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;
}
}
.navbar-bottom.navbar {
text-align: center;
border-radius: 0;
}
.crop-image, .member-image {
width: 100%;
height: 100%;
}
// Autosuggest
.ui-autocomplete {
z-index: @zindex-tooltip;
}
// Crowdfunding campaign, Sep-Oct 2014
.crowdfunding-banner {
text-align: center;
font-weight: bold;
background-color: lighten(@green, 30%);
margin-top: 0px;
margin-bottom: 5px;
padding: 15px;
}
.crowdfunding-banner a {
color: @brown;
text-decoration: underline;
}
// Overrides applying only to mobile view. This must be at the end of the overrides file.
@media only screen and (max-width: 767px) {
.sidebar {
margin-left: 0;
border-left: none;
padding-left: 0;
}
#map {
height: 300px;
}
.navbar .nav > li {
display: block;
}
}

View File

@@ -1,347 +0,0 @@
@import "bootstrap-sprockets"
@import "bootstrap"
@import "custom_bootstrap/variables"
// this padding needs to be done before the responsive stuff is imported
body
// modifying this for our promotional banner. can be replaced after if
// needed.
// padding-top: $navbar-height + 15px
padding-top: $navbar-height
//@import "bootstrap/responsive"
// Font Awesome
@import "font-awesome-sprockets"
@import "font-awesome"
// Glyphicons
//@import "bootstrap/glyphicons"
.list-inline > li.first
padding-left: 0px
h2
font-size: 150%
//#subtitle
// color: lighten($brown, 30%)
// font-style: italic
// font-weight: normal
// margin-top: 0px
// padding-left: 1em
// padding-top: 0px
h3
font-size: 120%
.main
padding-right: 1em
.navbar .navbar-form
padding-top: 0
padding-bottom: 0
margin-right: 0
margin-left: 15px
border: 0
-webkit-box-shadow: none
box-shadow: none
.img-responsive
max-width: 100%
height: auto
.sidebar
border-left: 1px solid darken($beige, 10%)
margin-left: -1px
padding-left: 1em
// this is used for eg. crops and members index pages
.six-across:nth-child(6n+1)
margin-left: 0px
.three-across:nth-child(3n+1)
margin-left: 0px
clear: both
// let's condense the hero unit a little
.jumbotron
padding-top: 30px
padding-bottom: 30px
// info under the main heading on homepage
.jumbotron .info
padding-top: 15px
// signup widget on homepage
.jumbotron .signup
background-color: lighten($green, 40%)
border: 1px solid lighten($green, 20%)
border-radius: 6px
line-height: 200%
padding: 15px
text-align: center
// stats shown on homepage. eg. "999 members..."
p.stats
font-weight: bold
.member-cards
display: flex
flex: none
flex-wrap: wrap
justify-content: space-between
.member-thumbnail
padding: .25em
div
width: 5em
display: inline-block
vertical-align: top
.member-thumbnail div~div
padding-left: 1em
width: 15em
.planting
dl.planting-attributes
dt
text-align: left
dd
margin-left: auto
@media (min-width: $screen-md-min)
.planting-thumbnail
dl.planting-attributes
width: 100%
dt
text-align: left
width: 120px
dd
padding-left: 120px
margin-left: auto
.navbar .navbar-form
width: 250px
#placesmap, #cropmap
height: 500px
#membermap
height: 250px
.location-not-set
height: 250px
width: 100%
background-image: image-url('location-not-set.en.png')
background-repeat: no-repeat
background-position: center
.member-location
font-size: small
font-style: italic
.member-location a
color: $brown
.photo-thumbnail
padding: 0
position: relative
img
width: 100%
.text
display: none
color: #000
position: absolute
bottom: 0
background: rgba(0, 0, 0, 0.8)
width: 100%
margin: 0
p
padding: 5px
margin: 0
color: #fff
&:hover
.text
display: block
.thumbnail
border: none
text-align: center
margin-bottom: 1.5em
.member-thumbnail
text-align: left
img
height: 85px
width: 85px
max-width: 85px
.crop-thumbnail
height: 220px
.cropinfo
display: inline-block
max-width: 100%
white-space: nowrap
line-height: 1em
padding-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
li.crop-hierarchy
list-style-type: disc
.navbar-brand
margin: 0px
padding: 0px
.navbar-bottom
margin: 40px 0px 0px 0px !important
// footer
footer
#footer1, #footer2, #footer3
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
// 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%
// Autosuggest
.ui-autocomplete
background: white
z-index: $zindex-tooltip
.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)
.sidebar
margin-left: 0
border-left: none
padding-left: 0
#map
height: 300px
.navbar .nav > li
display: block
.navbar .navbar-form
width: 185px
padding-left: 0
padding-right: 0
/* override "info" alert boxes to be green, not blue, on Growstuff */
$state-info-text: darken($green, 10%)
$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%)
.hide
display: none
#add-sci_name-row, #remove-sci_name-row, #add-alt_name-row, #remove-alt_name-row
display: none
.panel-footer
height: 6em
.panel
.dl-horizontal
text-overflow: ellipsis
overflow: hidden
.form-group.required .control-label:before
content: "* "
color: red
.margin-bottom
margin-bottom: 1em
.red
color: red
.truncate
overflow: hidden
text-overflow: ellipsis
white-space: nowrap
ul.plantings
list-style-type: none
ul.thumbnail-buttons
list-style-type: none
text-align: right
.hover-wrapper .text
position: absolute
visibility: hidden
.hover-wrapper:hover .text
visibility: visible

View File

@@ -0,0 +1,2 @@
class AboutController < ApplicationController
end

View File

@@ -1,53 +1,72 @@
class AccountTypesController < ApplicationController
before_action :authenticate_member!
before_filter :authenticate_member!
load_and_authorize_resource
respond_to :html
# GET /account_types
def index
@account_types = AccountType.all.order(:name)
respond_with(@account_types)
@account_types = AccountType.all
respond_to do |format|
format.html # index.html.erb
end
end
# GET /account_types/1
def show
respond_with(@account_types)
@account_type = AccountType.find(params[:id])
respond_to do |format|
format.html # show.html.erb
end
end
# GET /account_types/new
def new
@account_type = AccountType.new
respond_with(@account_type)
respond_to do |format|
format.html # new.html.erb
end
end
# GET /account_types/1/edit
def edit
respond_with(@account_type)
@account_type = AccountType.find(params[:id])
end
# POST /account_types
def create
@account_type = AccountType.new(account_type_params)
flash[:notice] = I18n.t('account_types.created') if @account_type.save
respond_with(@account_type)
@account_type = AccountType.new(params[:account_type])
respond_to do |format|
if @account_type.save
format.html { redirect_to @account_type, notice: 'Account type was successfully created.' }
else
format.html { render action: "new" }
end
end
end
# PUT /account_types/1
def update
flash[:notice] = I18n.t('account_types.updated') if @account_type.update(account_type_params)
respond_with(@account_type)
@account_type = AccountType.find(params[:id])
respond_to do |format|
if @account_type.update_attributes(params[:account_type])
format.html { redirect_to @account_type, notice: 'Account type was successfully updated.' }
else
format.html { render action: "edit" }
end
end
end
# DELETE /account_types/1
def destroy
@account_type = AccountType.find(params[:id])
@account_type.destroy
flash[:notice] = I18n.t('account_types.deleted')
respond_with(@account_type)
end
private
def account_type_params
params.require(:account_type).permit(:is_paid, :is_permanent_paid, :name)
respond_to do |format|
format.html { redirect_to account_types_url, notice: 'Account type was successfully deleted.' }
end
end
end

View File

@@ -1,31 +1,41 @@
class AccountsController < ApplicationController
before_action :authenticate_member!
before_filter :authenticate_member!
load_and_authorize_resource
respond_to :html
# GET /accounts
def index
@accounts = Account.all.order(created_at: :desc)
respond_with(@accounts)
@accounts = Account.all
respond_to do |format|
format.html # index.html.erb
end
end
# GET /accounts/1
def show
respond_with(@account)
@account = Account.find(params[:id])
respond_to do |format|
format.html # show.html.erb
end
end
# GET /accounts/1/edit
def edit; end
def edit
@account = Account.find(params[:id])
end
# PUT /accounts/1
def update
flash[:notice] = I18n.t('account.update') if @account.update(params[:account])
respond_with(@account)
@account = Account.find(params[:id])
respond_to do |format|
if @account.update_attributes(params[:account])
format.html { redirect_to @account, notice: 'Account detail was successfully updated.' }
else
format.html { render action: "edit" }
end
end
end
private
def account_params
params.require(:account).permit(:account_type_id, :member_id, :paid_until)
end
end

View File

@@ -1,14 +0,0 @@
module Admin
class MembersController < ApplicationController
before_action :auth!
def index
@members = Member.order(:login_name).paginate(page: params[:page])
end
private
def auth!
authorize! :manage, :all
end
end
end

View File

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

View File

@@ -1,12 +1,16 @@
class AdminController < ApplicationController
respond_to :html
def index
authorize! :manage, :all
respond_to do |format|
format.html # index.html.haml
end
end
def newsletter
authorize! :manage, :all
@members = Member.confirmed.wants_newsletter.all
respond_with @members
respond_to do |format|
format.html # index.html.haml
end
end
end

View File

@@ -1,60 +1,91 @@
class AlternateNamesController < ApplicationController
before_action :authenticate_member!, except: %i(index show)
before_filter :authenticate_member!, :except => [:index, :show]
load_and_authorize_resource
respond_to :html, :json
responders :flash
# GET /alternate_names
# GET /alternate_names.json
def index
@alternate_names = AlternateName.all.order(:name)
respond_with(@alternate_names)
@alternate_names = AlternateName.all
respond_to do |format|
format.html # index.html.haml
format.json { render json: @alternate_names }
end
end
# GET /alternate_names/1
# GET /alternate_names/1.json
def show
@alternate_name = AlternateName.find(params[:id])
respond_to do |format|
format.html # show.html.haml
format.json { render json: @alternate_name }
end
end
# GET /alternate_names/new
# GET /alternate_names/new.json
def new
@alternate_name = AlternateName.new
@crop = Crop.find_or_initialize_by(id: params[:crop_id])
@crop = Crop.find_by_id(params[:crop_id]) || Crop.new
respond_to do |format|
format.html # new.html.haml
format.json { render json: @alternate_name }
end
end
# GET /alternate_names/1/edit
def edit; end
def edit
@alternate_name = AlternateName.find(params[:id])
end
# POST /alternate_names
# POST /alternate_names.json
def create
params[:alternate_name][:creator_id] = current_member.id
@alternate_name = AlternateName.new(alternate_name_params)
@alternate_name = AlternateName.new(params[:alternate_name])
if @alternate_name.save
redirect_to @alternate_name.crop, notice: 'Alternate name was successfully created.'
else
render action: "new"
respond_to do |format|
if @alternate_name.save
format.html { redirect_to @alternate_name.crop, notice: 'Alternate name was successfully created.' }
format.json { render json: @alternate_name, status: :created, location: @alternate_name }
else
format.html { render action: "new" }
format.json { render json: @alternate_name.errors, status: :unprocessable_entity }
end
end
end
# PUT /alternate_names/1
# PUT /alternate_names/1.json
def update
if @alternate_name.update(alternate_name_params)
redirect_to @alternate_name.crop, notice: 'Alternate name was successfully updated.'
else
render action: "edit"
@alternate_name = AlternateName.find(params[:id])
respond_to do |format|
if @alternate_name.update_attributes(params[:alternate_name])
format.html { redirect_to @alternate_name.crop, notice: 'Alternate name was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @alternate_name.errors, status: :unprocessable_entity }
end
end
end
# DELETE /alternate_names/1
# DELETE /alternate_names/1.json
def destroy
@alternate_name = AlternateName.find(params[:id])
@crop = @alternate_name.crop
@alternate_name.destroy
redirect_to @crop, notice: 'Alternate name was successfully deleted.'
end
private
def alternate_name_params
params.require(:alternate_name).permit(:crop_id, :name, :creator_id)
respond_to do |format|
format.html {
redirect_to @crop, notice: 'Alternate name was successfully deleted.'
}
format.json { head :no_content }
end
end
end

View File

@@ -1,7 +0,0 @@
module Api
module V1
class BaseController < JSONAPI::ResourceController
abstract
end
end
end

View File

@@ -1,6 +1,13 @@
module Api
module V1
class CropsController < BaseController
end
class Api::V1::CropsController < ApplicationController
# GET /api/v1/crops
def index
@crops = Crop.all
end
# GET /crops/1
def show
@crop = Crop.find(params[:id])
end
end

View File

@@ -1,6 +0,0 @@
module Api
module V1
class GardensController < BaseController
end
end
end

View File

@@ -1,6 +0,0 @@
module Api
module V1
class HarvestsController < BaseController
end
end
end

View File

@@ -1,6 +0,0 @@
module Api
module V1
class MembersController < BaseController
end
end
end

View File

@@ -1,6 +0,0 @@
module Api
module V1
class PhotosController < BaseController
end
end
end

View File

@@ -1,6 +0,0 @@
module Api
module V1
class PlantingsController < BaseController
end
end
end

View File

@@ -1,6 +0,0 @@
module Api
module V1
class SeedsController < BaseController
end
end
end

View File

@@ -3,17 +3,18 @@ class ApplicationController < ActionController::Base
include ApplicationHelper
after_action :store_location
before_action :set_locale
after_filter :store_location
before_filter :set_locale
def store_location
unless request.path.in?(["/members/sign_in",
"/members/sign_up",
"/members/password/new",
"/members/password/edit",
"/members/confirmation",
"/members/sign_out"]) || request.xhr?
store_location_for(:member, request.fullpath)
if (request.path != "/members/sign_in" &&
request.path != "/members/sign_up" &&
request.path != "/members/password/new" &&
request.path != "/members/password/edit" &&
request.path != "/members/confirmation" &&
request.path != "/members/sign_out" &&
!request.xhr?)
store_location_for(:member, request.fullpath)
end
end
@@ -21,10 +22,6 @@ class ApplicationController < ActionController::Base
stored_location_for(:member) || root_path
end
def after_sign_out_path_for(resource_or_scope)
request.referer
end
# tweak CanCan defaults because we don't have a "current_user" method
# this means that we use current_user in specs but current_member everywhere
# else in the code.
@@ -34,9 +31,9 @@ class ApplicationController < ActionController::Base
# CanCan error handling
rescue_from CanCan::AccessDenied do |exception|
redirect_to request.referer || root_url, alert: exception.message
redirect_to request.referer || root_url, :alert => exception.message
end
def set_locale
I18n.locale = params[:locale] || extract_locale_from_subdomain || I18n.default_locale
end
@@ -46,37 +43,4 @@ 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.permit(: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.permit(: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
def expire_homepage
expire_fragment("homepage_stats")
end
end

View File

@@ -1,27 +1,38 @@
require './lib/actions/oauth_signup_action'
class AuthenticationsController < ApplicationController
before_action :authenticate_member!
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']
@authentication = nil
if auth
name = Growstuff::OauthSignupAction.new.determine_name(auth)
@authentication = current_member.authentications
.create_with(
name: name,
token: auth['credentials']['token'],
secret: auth['credentials']['secret']
)
.find_or_create_by(
provider: auth['provider'],
uid: auth['uid'],
name: name
)
name = ''
case auth['provider']
when 'twitter'
name = auth['info']['nickname']
when 'flickr'
name = auth['info']['name']
else
name = auth['info']['name']
end
@authentication = current_member.authentications.find_or_create_by_provider_and_uid(
:provider => auth['provider'],
:uid => auth['uid'],
:name => name,
:token => auth['credentials']['token'],
:secret => auth['credentials']['secret'])
flash[:notice] = "Authentication successful."
else
flash[:notice] = "Authentication failed."
@@ -31,6 +42,7 @@ class AuthenticationsController < ApplicationController
# DELETE /authentications/1
def destroy
@authentication = Authentication.find(params[:id])
@authentication.destroy
respond_to do |format|

View File

@@ -1,53 +1,104 @@
class CommentsController < ApplicationController
before_action :authenticate_member!, except: %i(index show)
before_filter :authenticate_member!, :except => [:index, :show]
load_and_authorize_resource
respond_to :html, :json
respond_to :rss, only: :index
responders :flash
cache_sweeper :comment_sweeper
# GET /comments
# GET /comments.json
def index
@comments = Comment.order(created_at: :desc).paginate(page: params[:page])
respond_with(@comments)
end
@comments = Comment.paginate(:page => params[:page])
def new
@comment = Comment.new
@post = Post.find_by(id: params[:post_id])
if @post
@comments = @post.comments
respond_with(@comments)
else
redirect_to(request.referer || root_url,
alert: "Can't post a comment on a non-existent post")
respond_to do |format|
format.html # index.html.erb
format.json { render json: @comments }
format.rss { render :layout => false }
end
end
# GET /comments/1
# GET /comments/1.json
def show
@comment = Comment.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: @comment }
end
end
# GET /comments/new
# GET /comments/new.json
def new
@comment = Comment.new
@post = Post.find_by_id(params[:post_id])
if @post
@comments = @post.comments
respond_to do |format|
format.html # new.html.erb
format.json { render json: @comment }
end
else
redirect_to request.referer || root_url,
:alert => "Can't post a comment on a non-existent post"
end
end
# GET /comments/1/edit
def edit
@comment = Comment.find(params[:id])
@comments = @comment.post.comments
end
# POST /comments
# POST /comments.json
def create
@comment = Comment.new(comment_params)
@comment.author = current_member
@comment.save
respond_with @comment, location: @comment.post
params[:comment][:author_id] = current_member.id
@comment = Comment.new(params[:comment])
respond_to do |format|
if @comment.save
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" }
format.json { render json: @comment.errors, status: :unprocessable_entity }
end
end
end
# PUT /comments/1
# PUT /comments/1.json
def update
@comment.update(body: comment_params['body'])
respond_with @comment, location: @comment.post
@comment = Comment.find(params[:id])
# you should never be able to change the author or post when
# updating
params[:comment].delete("post_id")
params[:comment].delete("author_id")
respond_to do |format|
if @comment.update_attributes(params[:comment])
format.html { redirect_to @comment.post, notice: 'Comment was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @comment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
@comment = Comment.find(params[:id])
@post = @comment.post
@comment.destroy
respond_with(@post)
end
private
def comment_params
params.require(:comment).permit(:body, :post_id)
respond_to do |format|
format.html { redirect_to @post }
format.json { head :no_content }
end
end
end

View File

@@ -1,194 +1,147 @@
require 'will_paginate/array'
class CropsController < ApplicationController
before_action :authenticate_member!, except: %i(index hierarchy search show)
before_filter :authenticate_member!, :except => [:index, :hierarchy, :search, :show]
load_and_authorize_resource
skip_authorize_resource only: %i(hierarchy search)
respond_to :html, :json, :rss, :csv
responders :flash
skip_authorize_resource :only => [:hierarchy, :search]
cache_sweeper :crop_sweeper
# GET /crops
# GET /crops.json
def index
@sort = params[:sort]
@crops = crops
@num_requested_crops = requested_crops.size if current_member
@filename = filename
respond_with @crops
end
def requested
@requested = requested_crops.paginate(page: params[:page])
respond_with @requested
if @sort == 'alpha'
# alphabetical order
@crops = Crop.includes(:scientific_names, {:plantings => :photos}).paginate(:page => params[:page])
else
# default to sorting by popularity
@crops = Crop.popular.includes(:scientific_names, {:plantings => :photos}).paginate(:page => params[:page])
end
respond_to do |format|
format.html
format.json { render :json => @crops }
format.rss do
@crops = Crop.recent.includes(:scientific_names, :creator)
render :rss => @crops
end
format.csv do
@filename = "Growstuff-Crops-#{Time.zone.now.to_s(:number)}.csv"
@crops = Crop.includes(:scientific_names, :plantings, :seeds, :creator)
render :csv => @crops
end
end
end
# GET /crops/wrangle
def wrangle
@approval_status = params[:approval_status]
@crops = case @approval_status
when "pending"
Crop.pending_approval
when "rejected"
Crop.rejected
else
Crop.recent
end.paginate(page: params[:page])
@crops = Crop.recent.paginate(:page => params[:page])
@crop_wranglers = Role.crop_wranglers
respond_with @crops
respond_to do |format|
format.html
end
end
# GET /crops/hierarchy
def hierarchy
@crops = Crop.toplevel
respond_with @crops
respond_to do |format|
format.html
end
end
# GET /crops/search
def search
@term = params[:term]
@matches = Crop.search(@term)
@paginated_matches = @matches.paginate(page: params[:page])
@search = params[:search]
@exact_match = Crop.find_by_name(params[:search])
respond_with @matches
@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])
respond_to do |format|
format.html
format.json { render :json => @fuzzy }
end
end
# GET /crops/1
# GET /crops/1.json
def show
@crop = Crop.includes(:scientific_names, plantings: :photos).find(params[:id])
@posts = @crop.posts.order(created_at: :desc).paginate(page: params[:page])
@crop = Crop.includes(:scientific_names, {:plantings => :photos}).find(params[:id])
@posts = @crop.posts.paginate(:page => params[:page])
respond_to do |format|
format.html # show.html.haml
format.json { render json: @crop.to_json(crop_json_fields) }
format.json do
render :json => @crop.to_json(:include => {
:plantings => { :include => { :owner => { :only => [:id, :login_name, :location, :latitude, :longitude] }}}
})
end
end
end
# GET /crops/new
# GET /crops/new.json
def new
@crop = Crop.new
@crop.alternate_names.build
@crop.scientific_names.build
respond_with @crop
3.times do
@crop.scientific_names.build
end
respond_to do |format|
format.html # new.html.haml
format.json { render json: @crop }
end
end
# GET /crops/1/edit
def edit
@crop.alternate_names.build if @crop.alternate_names.blank?
@crop.scientific_names.build if @crop.scientific_names.blank?
@crop = Crop.find(params[:id])
end
# POST /crops
# POST /crops.json
def create
@crop = Crop.new(crop_params)
params[:crop][:creator_id] = current_member.id
@crop = Crop.new(params[:crop])
if current_member.role? :crop_wrangler
@crop.creator = current_member
else
@crop.requester = current_member
@crop.approval_status = "pending"
respond_to do |format|
if @crop.save
format.html { redirect_to @crop, notice: 'Crop was successfully created.' }
format.json { render json: @crop, status: :created, location: @crop }
else
format.html { render action: "new" }
format.json { render json: @crop.errors, status: :unprocessable_entity }
end
end
notify_wranglers if Crop.transaction { @crop.save && save_crop_names }
respond_with @crop
end
# PUT /crops/1
# PUT /crops/1.json
def update
previous_status = @crop.approval_status
@crop = Crop.find(params[:id])
@crop.creator = current_member if previous_status == "pending"
if @crop.update(crop_params)
recreate_names('alt_name', 'alternate')
recreate_names('sci_name', 'scientific')
notifier.deliver_now! if previous_status == "pending"
respond_to do |format|
if @crop.update_attributes(params[:crop])
format.html { redirect_to @crop, notice: 'Crop was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @crop.errors, status: :unprocessable_entity }
end
end
respond_with @crop
end
# DELETE /crops/1
# DELETE /crops/1.json
def destroy
@crop = Crop.find(params[:id])
@crop.destroy
respond_with @crop
end
private
def notifier
case @crop.approval_status
when "approved"
Notifier.crop_request_approved(@crop.requester, @crop)
when "rejected"
Notifier.crop_request_rejected(@crop.requester, @crop)
respond_to do |format|
format.html { redirect_to crops_url }
format.json { head :no_content }
end
end
def save_crop_names
params[:alt_name]&.values&.each do |value|
create_name!('alternate', value) unless value.empty?
end
params[:sci_name]&.values&.each do |value|
create_name!('scientific', value) unless value.empty?
end
end
def notify_wranglers
return if current_member.role? :crop_wrangler
Role.crop_wranglers.each do |w|
Notifier.new_crop_request(w, @crop).deliver_now!
end
end
def recreate_names(param_name, name_type)
return if params[param_name].blank?
destroy_names(name_type)
params[param_name].each do |_i, value|
create_name!(name_type, value) unless value.empty?
end
end
def destroy_names(name_type)
@crop.send("#{name_type}_names").each(&:destroy)
end
def create_name!(name_type, value)
@crop.send("#{name_type}_names").create!(name: value, creator_id: current_member.id)
end
def crop_params
params.require(:crop).permit(:en_wikipedia_url,
:name,
:parent_id,
:creator_id,
:perennial,
:approval_status,
:request_notes,
:reason_for_rejection,
:rejection_notes,
scientific_names_attributes: %i(scientific_name
_destroy
id))
end
def filename
"Growstuff-Crops-#{Time.zone.now.to_s(:number)}.csv"
end
def crop_json_fields
{
include: {
plantings: {
include: {
owner: { only: %i(id login_name location latitude longitude) }
}
},
scientific_names: { only: [:name] },
alternate_names: { only: [:name] }
}
}
end
def crops
q = Crop.approved.includes(:scientific_names, plantings: :photos)
q = q.popular unless @sort == 'alpha'
q.order("LOWER(crops.name)").includes(:photos).paginate(page: params[:page])
end
def requested_crops
current_member.requested_crops.pending_approval
end
end

View File

@@ -1,14 +1,11 @@
class FollowsController < ApplicationController
before_action :authenticate_member!
load_and_authorize_resource
skip_load_resource only: :create
# POST /follows
def create
@follow = current_member.follows.build(followed_id: follow_params[:followed_id])
@follow = current_member.follows.build(:followed_id => params[:followed_id])
if @follow.save
flash[:notice] = "Followed #{@follow.followed.login_name}"
flash[:notice] = "Followed #{ @follow.followed.login_name }"
redirect_to :back
else
flash[:error] = "Already following or error while following."
@@ -18,17 +15,11 @@ class FollowsController < ApplicationController
# DELETE /follows/1
def destroy
@follow = current_member.follows.find(follow_params[:id])
@follow = current_member.follows.find(params[:id])
unfollowed_name = @follow.followed.login_name
@follow.destroy
flash[:notice] = "Unfollowed #{unfollowed_name}"
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

View File

@@ -1,56 +1,87 @@
class ForumsController < ApplicationController
load_and_authorize_resource
respond_to :html, :json
cache_sweeper :forum_sweeper
# GET /forums
# GET /forums.json
def index
@forums = Forum.all.order(:name)
respond_with(@forums)
@forums = Forum.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: @forums }
end
end
# GET /forums/1
# GET /forums/1.json
def show
respond_with(@forum)
@forum = Forum.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: @forum }
end
end
# GET /forums/new
# GET /forums/new.json
def new
@forum = Forum.new
respond_with(@forum)
respond_to do |format|
format.html # new.html.erb
format.json { render json: @forum }
end
end
# GET /forums/1/edit
def edit; end
def edit
@forum = Forum.find(params[:id])
end
# POST /forums
# POST /forums.json
def create
@forum = Forum.new(forum_params)
flash[:notice] = 'Forum was successfully created.' if @forum.save
respond_with(@forum)
@forum = Forum.new(params[:forum])
respond_to do |format|
if @forum.save
format.html { redirect_to @forum, notice: 'Forum was successfully created.' }
format.json { render json: @forum, status: :created, location: @forum }
else
format.html { render action: "new" }
format.json { render json: @forum.errors, status: :unprocessable_entity }
end
end
end
# PUT /forums/1
# PUT /forums/1.json
def update
flash[:notice] = 'Forum was successfully updated.' if @forum.update(forum_params)
respond_with(@forum)
@forum = Forum.find(params[:id])
respond_to do |format|
if @forum.update_attributes(params[:forum])
format.html { redirect_to @forum, notice: 'Forum was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @forum.errors, status: :unprocessable_entity }
end
end
end
# DELETE /forums/1
# DELETE /forums/1.json
def destroy
@forum = Forum.find(params[:id])
@forum.destroy
flash[:notice] = 'Forum was successfully deleted'
redirect_to forums_url
end
private
def forum_params
params.require(:forum).permit(:description, :name, :owner_id, :slug)
respond_to do |format|
format.html { redirect_to forums_url, notice: 'Forum was successfully deleted' }
format.json { head :no_content }
end
end
end

View File

@@ -1,73 +1,93 @@
class GardensController < ApplicationController
before_action :authenticate_member!, except: %i(index show)
after_action :expire_homepage, only: %i(create delete)
before_filter :authenticate_member!, :except => [:index, :show]
load_and_authorize_resource
respond_to :html, :json
cache_sweeper :garden_sweeper
# GET /gardens
# GET /gardens.json
def index
@owner = Member.find_by(slug: params[:owner])
@show_all = params[:all] == '1'
@gardens = gardens
respond_with(@gardens)
@gardens = Garden.paginate(:page => params[:page])
@owner = Member.find_by_slug(params[:owner])
if @owner
@gardens = @owner.gardens.paginate(:page => params[:page])
end
respond_to do |format|
format.html # index.html.erb
format.json { render json: @gardens }
end
end
# GET /gardens/1
# GET /gardens/1.json
def show
@current_plantings = @garden.plantings.current
.includes(:crop, :owner)
.order(planted_at: :desc)
@finished_plantings = @garden.plantings.finished
.includes(:crop)
.order(finished_at: :desc)
respond_with(@garden)
@garden = Garden.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: @garden }
end
end
# GET /gardens/new
# GET /gardens/new.json
def new
@garden = Garden.new
respond_with(@garden)
respond_to do |format|
format.html # new.html.erb
format.json { render json: @garden }
end
end
# GET /gardens/1/edit
def edit; end
def edit
@garden = Garden.find(params[:id])
end
# POST /gardens
# POST /gardens.json
def create
@garden.owner_id = current_member.id
flash[:notice] = I18n.t('gardens.created') if @garden.save
respond_with(@garden)
params[:garden][:owner_id] = current_member.id
@garden = Garden.new(params[:garden])
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 }
else
format.html { render action: "new" }
format.json { render json: @garden.errors, status: :unprocessable_entity }
end
end
end
# PUT /gardens/1
# PUT /gardens/1.json
def update
flash[:notice] = I18n.t('gardens.updated') if @garden.update(garden_params)
respond_with(@garden)
@garden = Garden.find(params[:id])
respond_to do |format|
if @garden.update_attributes(params[:garden])
format.html { redirect_to @garden, notice: 'Garden was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @garden.errors, status: :unprocessable_entity }
end
end
end
# DELETE /gardens/1
# DELETE /gardens/1.json
def destroy
@garden = Garden.find(params[:id])
@garden.destroy
flash[:notice] = I18n.t('gardens.deleted')
redirect_to(gardens_by_owner_path(owner: @garden.owner))
end
private
def garden_params
params.require(:garden).permit(:name, :slug, :description, :active,
:location, :latitude, :longitude, :area, :area_unit)
end
def gardens
g = @owner ? @owner.gardens : Garden.all
g = g.active unless @show_all
g.joins(:owner).order(:name).paginate(page: params[:page])
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
end

View File

@@ -1,98 +1,105 @@
class HarvestsController < ApplicationController
before_action :authenticate_member!, except: %i(index show)
after_action :update_crop_medians, only: %i(create update destroy)
before_filter :authenticate_member!, :except => [:index, :show]
load_and_authorize_resource
respond_to :html, :json
respond_to :csv, only: :index
responders :flash
# GET /harvests
# GET /harvests.json
def index
@owner = Member.find_by(slug: params[:owner]) if params[:owner]
@crop = Crop.find_by(slug: params[:crop]) if params[:crop]
@planting = Planting.find_by(slug: params[:planting_id]) if params[:planting_id]
@harvests = harvests
@filename = csv_filename
respond_with(@harvests)
end
def show
@matching_plantings = matching_plantings if @harvest.owner == current_member
@photos = @harvest.photos.order(created_at: :desc).paginate(page: params[:page])
respond_with(@harvest)
end
def new
@harvest = Harvest.new(harvested_at: Time.zone.today)
@planting = Planting.find_by(slug: params[:planting_id]) if params[:planting_id]
@crop = Crop.find_by(id: params[:crop_id])
respond_with(@harvest)
end
def edit
@planting = @harvest.planting if @harvest.planting_id
end
def create
@harvest.crop_id = @harvest.planting.crop_id if @harvest.planting_id
@harvest.harvested_at = Time.zone.now if @harvest.harvested_at.blank?
@harvest.save
respond_with(@harvest)
end
def update
@harvest.update(harvest_params)
respond_with(@harvest)
end
def destroy
@harvest.destroy
respond_with(@harvest)
end
private
def harvest_params
params.require(:harvest)
.permit(:planting_id, :crop_id, :harvested_at, :description,
:quantity, :unit, :weight_quantity, :weight_unit,
:plant_part_id, :slug, :si_weight)
.merge(owner_id: current_member.id)
end
def matching_plantings
Planting.where(crop: @harvest.crop, owner: @harvest.owner)
.where('(planted_at IS NULL OR planted_at <= ?)', @harvest.harvested_at)
.where('(finished_at IS NULL OR finished_at >= ?)', @harvest.harvested_at)
end
def harvests
@owner = Member.find_by_slug(params[:owner])
@crop = Crop.find_by_slug(params[:crop])
if @owner
@owner.harvests
@harvests = @owner.harvests.includes(:owner, :crop)
elsif @crop
@crop.harvests
elsif @planting
@planting.harvests
@harvests = @crop.harvests.includes(:owner, :crop)
else
Harvest.all
end.order(harvested_at: :desc).joins(:owner, :crop).paginate(page: params[:page])
@harvests = Harvest.includes(:owner, :crop)
end
respond_to do |format|
format.html { @harvests = @harvests.paginate(:page => params[:page]) }
format.json { render json: @harvests }
format.csv do
specifics = (@owner ? "#{@owner.name}-" : @crop ? "#{@crop.name}-" : nil)
@filename = "Growstuff-#{specifics}Harvests-#{Time.zone.now.to_s(:number)}.csv"
render :csv => @harvests
end
end
end
def csv_filename
specifics = if @owner
"#{@owner.login_name}-"
elsif @crop
"#{@crop.name}-"
end
"Growstuff-#{specifics}Harvests-#{Time.zone.now.to_s(:number)}.csv"
# GET /harvests/1
# GET /harvests/1.json
def show
@harvest = Harvest.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: @harvest }
end
end
def update_crop_medians
# We only update medians to predict plantings
# if this harvest is not linked to a planting, then do nothing
return if @harvest.planting.nil?
# GET /harvests/new
# GET /harvests/new.json
def new
@harvest = Harvest.new('harvested_at' => Date.today)
@harvest.planting.update_harvest_days
@harvest.crop.update_harvest_medians
# using find_by_id here because it returns nil, unlike find
@crop = Crop.find_by_id(params[:crop_id]) || Crop.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: @harvest }
end
end
# GET /harvests/1/edit
def edit
@harvest = Harvest.find(params[:id])
end
# POST /harvests
# POST /harvests.json
def create
params[:harvest][:owner_id] = current_member.id
params[:harvested_at] = parse_date(params[:harvested_at])
@harvest = Harvest.new(params[:harvest])
respond_to do |format|
if @harvest.save
format.html { redirect_to @harvest, notice: 'Harvest was successfully created.' }
format.json { render json: @harvest, status: :created, location: @harvest }
else
format.html { render action: "new" }
format.json { render json: @harvest.errors, status: :unprocessable_entity }
end
end
end
# PUT /harvests/1
# PUT /harvests/1.json
def update
@harvest = Harvest.find(params[:id])
respond_to do |format|
if @harvest.update_attributes(params[:harvest])
format.html { redirect_to @harvest, notice: 'Harvest was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @harvest.errors, status: :unprocessable_entity }
end
end
end
# DELETE /harvests/1
# DELETE /harvests/1.json
def destroy
@harvest = Harvest.find(params[:id])
@harvest.destroy
respond_to do |format|
format.html { redirect_to harvests_url }
format.json { head :no_content }
end
end
end

View File

@@ -1,11 +1,16 @@
class HomeController < ApplicationController
skip_authorize_resource
respond_to :html
def index
# we were previously generating a lot of instance variables like
# @members_count and @interesting_crops in here, but now we call
# the relevant class methods directly in the view, so that fragment
# caching will be effective.
respond_to do |format|
format.html # index.html.haml
end
end
end

View File

@@ -1,57 +0,0 @@
class LikesController < ApplicationController
before_action :authenticate_member!
respond_to :html, :json
def create
@like = Like.new(member: current_member, likeable: find_likeable)
return failed(@like, message: 'Unable to like') unless @like.likeable && @like.save
success(@like, liked_by_member: true, status_code: :created)
end
def destroy
@like = Like.find_by(id: params[:id], member: current_member)
return failed(@like, message: 'Unable to unlike') unless @like && @like.destroy
success(@like, liked_by_member: false, status_code: :ok)
end
private
def find_likeable
Post.find(params[:post_id]) if params[:post_id]
end
def render_json(like, liked_by_member: true)
{
id: like.likeable.id,
liked_by_member: liked_by_member,
description: ActionController::Base.helpers.pluralize(like.likeable.likes.count, "like"),
url: like_path(like, format: :json)
}
end
def success(like, liked_by_member: nil, status_code: nil)
respond_to do |format|
format.html { redirect_to like.likeable }
format.json do
render(json: render_json(like, liked_by_member: liked_by_member),
status: status_code)
end
end
end
def failed(like, message)
respond_to do |format|
format.json { render(json: { 'error': message }, status: :forbidden) }
format.html do
flash[:error] = message
if like && like.likeable
redirect_to like.likeable
else
redirect_to root_path
end
end
end
end
end

View File

@@ -1,104 +1,47 @@
class MembersController < ApplicationController
load_and_authorize_resource except: %i(finish_signup unsubscribe view_follows view_followers show)
skip_authorize_resource only: %i(nearby unsubscribe finish_signup)
respond_to :html, :json, :rss
after_action :expire_homepage, only: :create
load_and_authorize_resource
cache_sweeper :member_sweeper
skip_authorize_resource :only => :nearby
def index
@sort = params[:sort]
@members = members
@members = Member.confirmed.paginate(:page => params[:page])
respond_to do |format|
format.html # index.html.haml
format.json { render json: @members.to_json(only: member_json_fields) }
format.json { render :json => @members.to_json(:only => [:id, :login_name, :slug, :bio, :created_at, :location, :latitude, :longitude]) }
end
end
def show
@member = Member.confirmed.find(params[:id])
@twitter_auth = @member.auth('twitter')
@flickr_auth = @member.auth('flickr')
@facebook_auth = @member.auth('facebook')
@posts = @member.posts
@gardens = @member.gardens.active.order(:name)
@member = Member.confirmed.find(params[:id])
@twitter_auth = @member.auth('twitter')
@flickr_auth = @member.auth('flickr')
@posts = @member.posts
# The garden form partial is called from the "New Garden" tab;
# it requires a garden to be passed in @garden.
# The new garden is not persisted unless Garden#save is called.
@garden = Garden.new
respond_to do |format|
format.html # show.html.haml
format.json { render json: @member.to_json(only: member_json_fields) }
format.rss do
render(
layout: false,
locals: { member: @member }
)
end
format.json { render :json => @member.to_json(:only => [:id, :login_name, :bio, :created_at, :slug, :location, :latitude, :longitude]) }
format.rss { render(
:layout => false,
:locals => { :member => @member }
)}
end
end
def view_follows
@member = Member.confirmed.find(params[:login_name])
@follows = @member.followed.paginate(page: params[:page])
@follows = @member.followed.paginate(:page => params[:page])
end
def view_followers
@member = Member.confirmed.find(params[:login_name])
@followers = @member.followers.paginate(page: params[:page])
@followers = @member.followers.paginate(:page => params[:page])
end
EMAIL_TYPE_STRING = {
send_notification_email: "direct message notifications",
send_planting_reminder: "planting reminders"
}.freeze
def unsubscribe
verifier = ActiveSupport::MessageVerifier.new(ENV['RAILS_SECRET_TOKEN'])
decrypted_message = verifier.verify(params[:message])
@member = Member.find(decrypted_message[:member_id])
@type = decrypted_message[:type]
@member.update(@type => false)
flash.now[:notice] = I18n.t('members.unsubscribed', email_type: EMAIL_TYPE_STRING[@type])
rescue ActiveSupport::MessageVerifier::InvalidSignature
flash.now[:alert] = I18n.t('members.unsubscribe.error')
end
def finish_signup
@member = current_member
return unless request.patch? && params[:member]
if @member.update(member_params)
@member.skip_reconfirmation!
bypass_sign_in(@member)
redirect_to root_path, notice: I18n.t('members.welcome')
else
flash[:alert] = I18n.t('members.signup.error')
@show_errors = true
end
end
private
def member_params
params.require(:member).permit(:login_name, :tos_agreement, :email, :newsletter)
end
def member_json_fields
%i(
id login_name
slug bio created_at
location latitude longitude
)
end
def members
if @sort == 'recently_joined'
Member.recently_joined
else
Member.order(:login_name)
end.confirmed.paginate(page: params[:page])
end
end

View File

@@ -1,65 +1,63 @@
class NotificationsController < ApplicationController
include NotificationsHelper
before_action :authenticate_member!
before_filter :authenticate_member!
load_and_authorize_resource
respond_to :html
# GET /notifications
def index
@notifications = Notification.by_recipient(current_member).order(:created_at).page(params[:page])
@notifications = Notification.find_all_by_recipient_id(current_member)
respond_to do |format|
format.html # index.html.erb
end
end
# GET /notifications/1
def show
@notification = Notification.find(params[:id])
@notification.read = true
@notification.save
@reply_link = reply_link(@notification)
respond_to do |format|
format.html # show.html.erb
end
end
# GET /notifications/new
def new
@notification = Notification.new
@recipient = Member.find_by(id: params[:recipient_id])
@recipient = Member.find_by_id(params[:recipient_id])
@subject = params[:subject] || ""
end
# GET /notifications/1/reply
def reply
@notification = Notification.new
@sender_notification = Notification.find_by(id: params[:id], recipient: current_member)
@sender_notification.read = true
@sender_notification.save
@recipient = @sender_notification.sender
@subject = if @sender_notification.subject.start_with? 'Re: '
@sender_notification.subject
else
"Re: #{@sender_notification.subject}"
end
respond_to do |format|
format.html # new.html.erb
end
end
# DELETE /notifications/1
def destroy
@notification = Notification.find(params[:id])
@notification.destroy
redirect_to notifications_url
respond_to do |format|
format.html { redirect_to notifications_url }
end
end
# POST /notifications
def create
params[:notification][:sender_id] = current_member.id
@notification = Notification.new(notification_params)
@recipient = Member.find_by(id: params[:notification][:recipient_id])
@notification = Notification.new(params[:notification])
@recipient = Member.find_by_id(params[:notification][:recipient_id])
if @notification.save
redirect_to notifications_path, notice: 'Message was successfully sent.'
else
render action: "new"
respond_to do |format|
if @notification.save
format.html { redirect_to notifications_path, notice: 'Message was successfully sent.' }
else
format.html { render action: "new" }
end
end
end
private
def notification_params
params.require(:notification).permit(:sender_id, :recipient_id, :subject, :body, :post_id, :read)
end
end

View File

@@ -1,51 +0,0 @@
require './lib/actions/oauth_signup_action'
#
# Handle signup or signin
# from various oauth providers
#
# Heavily overlaps with Authentications controller
#
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
create
end
def failure
flash[:alert] = "Authentication failed."
redirect_to request.env['omniauth.origin'] || "/"
end
private
def create
auth = request.env['omniauth.auth']
action = Growstuff::OauthSignupAction.new
@authentication = nil
return redirect_to request.env['omniauth.origin'] || edit_member_registration_path unless auth
member = action.find_or_create_from_authorization(auth)
@authentication = action.establish_authentication(auth, member)
if action.member_created?
raise "Invalid provider" unless %w(facebook twitter flickr).index(auth['provider'].to_s)
session["devise.#{auth['provider']}_data"] = request.env["omniauth.auth"]
sign_in member
redirect_to finish_signup_url(member)
else
sign_in_and_redirect member, event: :authentication # this will throw if @user is not activated
set_flash_message(:notice, :success, kind: auth['provider']) if is_navigational_format?
end
end
def after_sign_in_path_for(resource)
if resource.tos_agreement
super resource
else
finish_signup_path(resource)
end
end
end

View File

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

View File

@@ -1,10 +1,10 @@
class OrdersController < ApplicationController
before_action :authenticate_member!
before_filter :authenticate_member!
load_and_authorize_resource
# GET /orders
def index
@orders = Order.by_member(current_member)
@orders = Order.find_all_by_member_id(current_member.id)
respond_to do |format|
format.html # index.html.erb
@@ -13,6 +13,8 @@ class OrdersController < ApplicationController
# GET /orders/1
def show
@order = Order.find(params[:id])
respond_to do |format|
format.html # show.html.erb
end
@@ -29,32 +31,37 @@ class OrdersController < ApplicationController
# checkout with PayPal
def checkout
@order = Order.find(params[:id])
respond_to do |format|
if @order.update_attributes(referral_code: params[:referral_code])
if @order.update_attributes(:referral_code => params[:referral_code])
response = EXPRESS_GATEWAY.setup_purchase(
@order.total,
items: @order.activemerchant_items,
currency: Growstuff::Application.config.currency,
no_shipping: true,
ip: request.remote_ip,
return_url: complete_order_url,
cancel_return_url: shop_url
:items => @order.activemerchant_items,
:currency => Growstuff::Application.config.currency,
:no_shipping => true,
:ip => request.remote_ip,
:return_url => complete_order_url,
:cancel_return_url => shop_url
)
format.html { redirect_to EXPRESS_GATEWAY.redirect_url_for(response.token) }
else
format.html { render action: "show" }
end
end
end
def complete
if params[:token] && params['PayerID']
@order = Order.find(params[:id])
if (params[:token] && params['PayerID'])
purchase = EXPRESS_GATEWAY.purchase(
@order.total,
currency: Growstuff::Application.config.currency,
ip: request.remote_ip,
payer_id: params['PayerID'],
token: params[:token]
:currency => Growstuff::Application.config.currency,
:ip => request.remote_ip,
:payer_id => params['PayerID'],
:token => params[:token]
)
if purchase.success?
@order.completed_at = Time.zone.now
@@ -71,9 +78,11 @@ class OrdersController < ApplicationController
respond_to do |format|
format.html # new.html.erb
end
end
def cancel
@order = Order.find(params[:id])
respond_to do |format|
format.html { redirect_to shop_url, notice: 'Order was cancelled.' }
end
@@ -81,6 +90,7 @@ class OrdersController < ApplicationController
# DELETE /orders/1
def destroy
@order = Order.find(params[:id])
@order.destroy
respond_to do |format|

View File

@@ -1,6 +0,0 @@
class PagesController < ApplicationController
def letsencrypt
# use your code here, not mine
render text: "y9KNck8wqkoQLnlr2RgA2TVwWtyYb4PeY_hzGNx0Tfs.dlIPqFhMDCLyQEccczY3roHZ1UWu6UqVeyb9mkRxheU"
end
end

View File

@@ -1,7 +1,7 @@
class PasswordsController < Devise::PasswordsController
protected
protected
def after_resetting_password_path_for(resource)
root_path
end
end
end

View File

@@ -1,21 +0,0 @@
class PhotoAssociationsController < ApplicationController
before_action :authenticate_member!
respond_to :json, :html
def destroy
raise "Photos not supported" unless Photo::PHOTO_CAPABLE.include? item_class
@photo = Photo.find_by!(id: params[:photo_id], owner: current_member)
@item = Photographing.item(item_id, item_class)
@item.photos.delete(@photo)
# @photo.destroy_if_unused
respond_with(@photo)
end
def item_class
params[:type].capitalize
end
def item_id
params[:id]
end
end

View File

@@ -1,109 +1,135 @@
class PhotosController < ApplicationController
before_action :authenticate_member!, except: %i(index show)
after_action :expire_homepage, only: %i(create delete)
before_filter :authenticate_member!, :except => [:index, :show]
load_and_authorize_resource
respond_to :html, :json
responders :flash
cache_sweeper :photo_sweeper
# GET /photos
# GET /photos.json
def index
if params[:crop_id]
@crop = Crop.find params[:crop_id]
@photos = @crop.photos
else
@photos = Photo.all
@photos = Photo.paginate(:page => params[:page])
respond_to do |format|
format.html # index.html.erb
format.json { render json: @photos }
end
@photos = @photos.order(created_at: :desc)
.includes(:owner)
.paginate(page: params[:page])
respond_with(@photos)
end
# GET /photos/1
# GET /photos/1.json
def show
@photo = Photo.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: @photo }
end
end
# GET /photos/new
# GET /photos/new.json
def new
@photo = Photo.new
@item = item_to_link_to
@type = item_type
@id = item_id
retrieve_from_flickr
respond_with @photo
end
def edit
respond_with @photo
end
def create
ActiveRecord::Base.transaction do
@photo = find_or_create_photo_from_flickr_photo
@item = item_to_link_to
raise "Could not find this #{type} owned by you" unless @item
@item.photos << @photo unless @item.photos.include? @photo
@photo.save! if @photo.present?
end
respond_with @photo
end
def update
@photo.update(photo_params)
respond_with @photo
end
def destroy
@photo.destroy
respond_with @photo
end
private
#
# Params
def item_id
params[:id]
end
def item_type
params[:type]
end
def flickr_photo_id_param
params[:photo][:flickr_photo_id]
end
def photo_params
params.require(:photo).permit(:flickr_photo_id, :title, :license_name,
:license_url, :thumbnail_url, :fullsize_url, :link_url)
end
# Item with photos attached
def item_to_link_to
raise "No item id provided" if item_id.nil?
raise "No item type provided" if item_type.nil?
item_class = item_type.capitalize
raise "Photos not supported" unless Photo::PHOTO_CAPABLE.include? item_class
item_class.constantize.find_by!(id: params[:id], owner_id: current_member.id)
end
#
# Flickr retrieval
def find_or_create_photo_from_flickr_photo
photo = Photo.find_by(flickr_photo_id: flickr_photo_id_param)
photo ||= Photo.new(photo_params)
photo.owner_id = current_member.id
photo.set_flickr_metadata
photo
end
def retrieve_from_flickr
@flickr_auth = current_member.auth('flickr')
@current_set = params[:set]
return unless @flickr_auth
@type = params[:type]
@id = params[:id]
page = params[:page] || 1
@sets = current_member.flickr_sets
photos, total = current_member.flickr_photos(page, @current_set)
@flickr_auth = current_member.auth('flickr')
@current_set = params[:set]
if @flickr_auth
@sets = current_member.flickr_sets
photos, total = current_member.flickr_photos(page, @current_set)
@photos = WillPaginate::Collection.create(page, 30, total) do |pager|
pager.replace photos
@photos = WillPaginate::Collection.create(page, 30, total) do |pager|
pager.replace photos
end
end
respond_to do |format|
format.html # new.html.erb
format.json { render json: @photo }
end
end
# GET /photos/1/edit
def edit
@photo = Photo.find(params[:id])
end
# POST /photos
# POST /photos.json
def create
@photo = Photo.find_by_flickr_photo_id(params[:photo][:flickr_photo_id]) ||
Photo.new(params[:photo])
@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"]
if params[:type]
if valid_models.include?(params[:type])
if params[:id]
item = params[:type].camelcase.constantize.find_by_id(params[:id])
if item
if item.owner.id == current_member.id
# This syntax is weird, so just know that it means this:
# @photo.harvests << item unless @photo.harvests.include?(item)
# but with the correct many-to-many relationship automatically referenced
(@photo.send "#{params[:type]}s") << item unless (@photo.send "#{params[:type]}s").include?(item)
else
flash[:alert] = "You must own both the #{params[:type]} and the photo."
end
else
flash[:alert] = "Couldn't find #{params[:type]} to connect to photo."
end
else
flash[:alert] = "Missing id parameter"
end
else
flash[:alert] = "Cannot attach photos to #{params[:type]}"
end
else
flash[:alert] = "Missing type parameter"
end
respond_to do |format|
if @photo.save
format.html { redirect_to @photo, notice: 'Photo was successfully added.' }
format.json { render json: @photo, status: :created, location: @photo }
else
format.html { render action: "new" }
format.json { render json: @photo.errors, status: :unprocessable_entity }
end
end
end
# PUT /photos/1
# PUT /photos/1.json
def update
@photo = Photo.find(params[:id])
respond_to do |format|
if @photo.update_attributes(params[:photo])
format.html { redirect_to @photo, notice: 'Photo was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @photo.errors, status: :unprocessable_entity }
end
end
end
# DELETE /photos/1
# DELETE /photos/1.json
def destroy
@photo = Photo.find(params[:id])
@photo.destroy
respond_to do |format|
format.html { redirect_to photos_url }
format.json { head :no_content }
end
end
end

View File

@@ -1,16 +1,11 @@
class PlacesController < ApplicationController
skip_authorize_resource
respond_to :html, :json
def index
respond_to do |format|
format.html
# json response is whatever we want to map here
format.json do
render json: Member.located.to_json(only: %i(
id login_name slug location latitude longitude
))
end
format.json { render :json => Member.located.to_json(:only => [:id, :login_name, :slug, :location, :latitude, :longitude]) }
end
end
@@ -21,19 +16,16 @@ class PlacesController < ApplicationController
@nearby_members = Member.nearest_to(params[:place])
respond_to do |format|
format.html # show.html.haml
format.json do
render json: @nearby_members.to_json(only: %i(
id login_name slug location latitude longitude
))
end
format.json { render :json => @nearby_members.to_json(:only => [:id, :login_name, :slug, :location, :latitude, :longitude]) }
end
end
def search
if params[:new_place].empty?
redirect_to places_path, alert: 'Please enter a valid location'
else
redirect_to place_path(params[:new_place])
respond_to do |format|
format.html do
redirect_to place_path(params[:new_place])
end
end
end
end

View File

@@ -1,42 +1,85 @@
class PlantPartsController < ApplicationController
load_and_authorize_resource
respond_to :html, :json
responders :flash
# GET /plant_parts
# GET /plant_parts.json
def index
@plant_parts = PlantPart.all.order(:name)
respond_with(@plant_parts)
@plant_parts = PlantPart.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: @plant_parts }
end
end
# GET /plant_parts/1
# GET /plant_parts/1.json
def show
respond_with(@plant_part)
@plant_part = PlantPart.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: @plant_part }
end
end
# GET /plant_parts/new
# GET /plant_parts/new.json
def new
@plant_part = PlantPart.new
respond_with(@plant_part)
respond_to do |format|
format.html # new.html.erb
format.json { render json: @plant_part }
end
end
def edit; end
# GET /plant_parts/1/edit
def edit
@plant_part = PlantPart.find(params[:id])
end
# POST /plant_parts
# POST /plant_parts.json
def create
@plant_part = PlantPart.create(plant_part_params)
respond_with(@plant_part)
@plant_part = PlantPart.new(params[:plant_part])
respond_to do |format|
if @plant_part.save
format.html { redirect_to @plant_part, notice: 'Plant part was successfully created.' }
format.json { render json: @plant_part, status: :created, location: @plant_part }
else
format.html { render action: "new" }
format.json { render json: @plant_part.errors, status: :unprocessable_entity }
end
end
end
# PUT /plant_parts/1
# PUT /plant_parts/1.json
def update
@plant_part.update(plant_part_params)
respond_with(@plant_part)
@plant_part = PlantPart.find(params[:id])
respond_to do |format|
if @plant_part.update_attributes(params[:plant_part])
format.html { redirect_to @plant_part, notice: 'Plant part was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @plant_part.errors, status: :unprocessable_entity }
end
end
end
# DELETE /plant_parts/1
# DELETE /plant_parts/1.json
def destroy
@plant_part = PlantPart.find(params[:id])
@plant_part.destroy
respond_with(@plant_part)
end
private
def plant_part_params
params.require(:plant_part).permit(:name, :slug)
respond_to do |format|
format.html { redirect_to plant_parts_url }
format.json { head :no_content }
end
end
end

View File

@@ -1,104 +1,115 @@
class PlantingsController < ApplicationController
before_action :authenticate_member!, except: %i(index show)
after_action :expire_homepage, only: %i(create update destroy)
after_action :update_crop_medians, only: %i(create update destroy)
after_action :update_planting_medians, only: :update
before_filter :authenticate_member!, :except => [:index, :show]
load_and_authorize_resource
respond_to :html, :json
respond_to :csv, :rss, only: [:index]
responders :flash
cache_sweeper :planting_sweeper
# GET /plantings
# GET /plantings.json
def index
@owner = Member.find_by(slug: params[:owner]) if params[:owner]
@crop = Crop.find_by(slug: params[:crop]) if params[:crop]
@show_all = params[:all] == '1'
@owner = Member.find_by_slug(params[:owner])
@crop = Crop.find_by_slug(params[:crop])
if @owner
@plantings = @owner.plantings.includes(:owner, :crop, :garden).paginate(:page => params[:page])
elsif @crop
@plantings = @crop.plantings.includes(:owner, :crop, :garden).paginate(:page => params[:page])
else
@plantings = Planting.includes(:owner, :crop, :garden).paginate(:page => params[:page])
end
@plantings = plantings
specifics = if @owner
"#{@owner.login_name}-"
elsif @crop
"#{@crop.name}-"
end
@filename = "Growstuff-#{specifics}Plantings-#{Time.zone.now.to_s(:number)}.csv"
respond_with(@plantings)
respond_to do |format|
format.html { @plantings = @plantings.paginate(:page => params[:page]) }
format.json { render json: @plantings }
format.rss { render :layout => false } #index.rss.builder
format.csv do
specifics = (@owner ? "#{@owner.name}-" : @crop ? "#{@crop.name}-" : nil)
@filename = "Growstuff-#{specifics}Plantings-#{Time.zone.now.to_s(:number)}.csv"
render :csv => @plantings
end
end
end
# GET /plantings/1
# GET /plantings/1.json
def show
@planting = Planting.includes(:owner, :crop, :garden, :photos)
.friendly
.find(params[:id])
@photos = @planting.photos.order(created_at: :desc).includes(:owner).paginate(page: params[:page])
respond_with @planting
@planting = Planting.includes(:owner, :crop, :garden, :photos).find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: @planting }
end
end
# GET /plantings/new
# GET /plantings/new.json
def new
@planting = Planting.new(planted_at: Time.zone.today)
@planting = Planting.new('planted_at' => Date.today)
# using find_by_id here because it returns nil, unlike find
@crop = Crop.approved.find_by(id: params[:crop_id]) || Crop.new
@garden = Garden.find_by(owner: current_member, id: params[:garden_id]) || Garden.new
@crop = Crop.find_by_id(params[:crop_id]) || Crop.new
@garden = Garden.find_by_id(params[:garden_id]) || Garden.new
respond_with @planting
respond_to do |format|
format.html # new.html.erb
format.json { render json: @planting }
end
end
# GET /plantings/1/edit
def edit
@planting = Planting.find(params[:id])
# the following are needed to display the form but aren't used
@crop = Crop.new
@garden = Garden.new
end
# POST /plantings
# POST /plantings.json
def create
@planting = Planting.new(planting_params)
@planting.owner = current_member
@planting.save!
respond_with @planting
params[:planting][:owner_id] = current_member.id
params[:planted_at] = parse_date(params[:planted_at])
@planting = Planting.new(params[:planting])
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 }
else
format.html { render action: "new" }
format.json { render json: @planting.errors, status: :unprocessable_entity }
end
end
end
# PUT /plantings/1
# PUT /plantings/1.json
def update
@planting.update(planting_params)
respond_with @planting
@planting = Planting.find(params[:id])
params[:planted_at] = parse_date(params[:planted_at])
respond_to do |format|
if @planting.update_attributes(params[:planting])
format.html { redirect_to @planting, notice: 'Planting was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @planting.errors, status: :unprocessable_entity }
end
end
end
# DELETE /plantings/1
# DELETE /plantings/1.json
def destroy
@planting = Planting.find(params[:id])
@garden = @planting.garden
@planting.destroy
respond_with @planting, location: @planting.garden
end
private
def update_crop_medians
@planting.crop.update_lifespan_medians
end
def update_planting_medians
@planting.update_harvest_days
end
def planting_params
params[:planted_at] = parse_date(params[:planted_at]) if params[:planted_at]
params.require(:planting).permit(
:crop_id, :description, :garden_id, :planted_at,
:quantity, :sunniness, :planted_from, :finished,
:finished_at
)
end
def plantings
p = if @owner
@owner.plantings
elsif @crop
@crop.plantings
else
Planting
end
p = p.current unless @show_all
p.joins(:owner, :crop, :garden)
.order(created_at: :desc)
.includes(:crop, :owner, :garden)
.paginate(page: params[:page])
respond_to do |format|
format.html { redirect_to @garden }
format.json { head :no_content }
end
end
end

View File

@@ -0,0 +1,2 @@
class PolicyController < ApplicationController
end

View File

@@ -1,71 +1,101 @@
class PostsController < ApplicationController
before_action :authenticate_member!, except: %i(index show)
before_filter :authenticate_member!, :except => [:index, :show]
load_and_authorize_resource
respond_to :html, :json
respond_to :rss, only: %i(index show)
cache_sweeper :post_sweeper
# GET /posts
# GET /posts.json
# GET /posts.rss
def index
@author = Member.find_by(slug: params[:author])
@posts = posts
respond_with(@posts)
@author = Member.find_by_slug(params[:author])
if @author
@posts = @author.posts.includes(:author, { :comments => :author }).paginate(:page => params[:page])
else
@posts = Post.includes(:author, { :comments => :author }).paginate(:page => params[:page])
end
respond_to do |format|
format.html # index.html.haml
format.json { render json: @posts }
format.rss { render :layout => false } #index.rss.builder
end
end
# GET /posts/1
# GET /posts/1.json
# GET /posts/1.rss
def show
@post = Post.includes(:author, comments: :author).find(params[:id])
respond_with(@post)
@post = Post.includes(:author, { :comments => :author }).find(params[:id])
respond_to do |format|
format.html # show.html.haml
format.json { render json: @post }
format.rss { render(
:layout => false,
:locals => { :post => @post }
)}
end
end
# GET /posts/new
# GET /posts/new.json
def new
@post = Post.new
@forum = Forum.find_by(id: params[:forum_id])
respond_with(@post)
@forum = Forum.find_by_id(params[:forum_id])
respond_to do |format|
format.html # new.html.haml
format.json { render json: @post }
end
end
# GET /posts/1/edit
def edit; end
def edit
@post = Post.find(params[:id])
end
# POST /posts
# POST /posts.json
def create
params[:post][:author_id] = current_member.id
@post = Post.new(post_params)
flash[:notice] = 'Post was successfully created.' if @post.save
respond_with(@post)
@post = Post.new(params[:post])
respond_to do |format|
if @post.save
format.html { redirect_to @post, notice: 'Post was successfully created.' }
format.json { render json: @post, status: :created, location: @post }
else
format.html { render action: "new" }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
# PUT /posts/1
# PUT /posts/1.json
def update
flash[:notice] = 'Post was successfully updated.' if @post.update(post_params)
respond_with(@post)
@post = Post.find(params[:id])
respond_to do |format|
if @post.update_attributes(params[:post])
format.html { redirect_to @post, notice: 'Post was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
flash[:notice] = 'Post was deleted.' if @post.destroy
respond_with(@post)
end
@post = Post.find(params[:id])
@post.destroy
private
def post_params
params.require(:post).permit(:body, :subject, :author_id, :forum_id)
end
def posts
if @author
@author.posts
else
Post
end.order(created_at: :desc).includes(:author, comments: :author).paginate(page: params[:page])
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was deleted.' }
format.json { head :no_content }
end
end
end

View File

@@ -1,46 +1,72 @@
class ProductsController < ApplicationController
before_action :authenticate_member!
before_filter :authenticate_member!
load_and_authorize_resource
respond_to :html
responders :flash
# GET /products
def index
@products = Product.all.order(:name)
respond_with @products
@products = Product.all
respond_to do |format|
format.html # index.html.erb
end
end
# GET /products/1
def show
respond_with @product
@product = Product.find(params[:id])
respond_to do |format|
format.html # show.html.erb
end
end
# GET /products/new
def new
@product = Product.new
respond_with @product
respond_to do |format|
format.html # new.html.erb
end
end
# GET /products/1/edit
def edit
respond_with @product
@product = Product.find(params[:id])
end
# POST /products
def create
@product = Product.create(product_params)
respond_with @product
@product = Product.new(params[:product])
respond_to do |format|
if @product.save
format.html { redirect_to @product, notice: 'Product was successfully created.' }
else
format.html { render action: "new" }
end
end
end
# PUT /products/1
def update
@product.update(product_params)
respond_with @product
@product = Product.find(params[:id])
respond_to do |format|
if @product.update_attributes(params[:product])
format.html { redirect_to @product, notice: 'Product was successfully updated.' }
else
format.html { render action: "edit" }
end
end
end
# DELETE /products/1
def destroy
@product = Product.find(params[:id])
@product.destroy
respond_with @product
end
private
def product_params
params.require(:product).permit(:description, :min_price, :recommended_price, :name,
:account_type_id, :paid_months)
respond_to do |format|
format.html { redirect_to products_url }
end
end
end

View File

@@ -1,52 +1,46 @@
class RegistrationsController < Devise::RegistrationsController
respond_to :json
cache_sweeper :member_sweeper
def edit
@twitter_auth = current_member.auth('twitter')
@flickr_auth = current_member.auth('flickr')
@facebook_auth = current_member.auth('facebook')
@twitter_auth = current_member.auth('twitter')
@flickr_auth = current_member.auth('flickr')
render "edit"
end
# we need this subclassed method so that Devise doesn't force people to
# change their password every time they want to edit their settings.
# we also check that they give their current password to change their password.
# Code copied from
# https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-account-without-providing-a-password
# we need this subclassed method so that Devise doesn't force people to
# change their password every time they want to edit their settings.
# we also check that they give their current password to change their password.
# Code copied from
# https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-account-without-providing-a-password
def update
@member = Member.find(current_member.id)
if needs_password?(@member, params)
successfully_updated = @member.update_with_password(devise_parameter_sanitizer.sanitize(:account_update))
successfully_updated = if needs_password?(@member, params)
@member.update_with_password(devise_parameter_sanitizer.sanitize(:account_update))
else
# remove the virtual current_password attribute
# update_without_password doesn't know how to ignore it
params[:member].delete(:current_password)
successfully_updated = @member.update_without_password(devise_parameter_sanitizer.sanitize(:account_update))
@member.update_without_password(devise_parameter_sanitizer.sanitize(:account_update))
end
if successfully_updated
set_flash_message :notice, :updated
# Sign in the member bypassing validation in case their password changed
sign_in @member, bypass: true
sign_in @member, :bypass => true
redirect_to edit_member_registration_path
else
render "edit"
end
end
def destroy
if @member.destroy_with_password(params.require(:member)[:current_password])
redirect_to root_path
else
render "edit"
end
end
end
# check if we need the current password to update fields
def needs_password?(member, params)
params[:member][:password].present? ||
params[:member][:password_confirmation].present?
params[:member][:password_confirmation].present?
end

View File

@@ -1,15 +0,0 @@
class RobotsController < ApplicationController
DEFAULT_FILENAME = 'config/robots.txt'.freeze
def robots
filename = "config/robots.#{subdomain}.txt" if subdomain && subdomain != 'www'
file_to_render = File.exist?(filename.to_s) ? filename : DEFAULT_FILENAME
render file: file_to_render, layout: false, content_type: 'text/plain'
end
private
def subdomain
request.subdomain.present? ? request.subdomain : nil
end
end

View File

@@ -1,45 +1,72 @@
class RolesController < ApplicationController
before_action :authenticate_member!
before_filter :authenticate_member!
load_and_authorize_resource
respond_to :html
responders :flash
# GET /roles
def index
@roles = Role.all.order(:name)
respond_with @roles
@roles = Role.all
respond_to do |format|
format.html # index.html.erb
end
end
# GET /roles/1
def show
respond_with @role
@role = Role.find(params[:id])
respond_to do |format|
format.html # show.html.erb
end
end
# GET /roles/new
def new
@role = Role.new
respond_with @role
respond_to do |format|
format.html # new.html.erb
end
end
# GET /roles/1/edit
def edit
respond_with @role
@role = Role.find(params[:id])
end
# POST /roles
def create
@role = Role.create(role_params)
respond_with @role
@role = Role.new(params[:role])
respond_to do |format|
if @role.save
format.html { redirect_to @role, notice: 'Role was successfully created.' }
else
format.html { render action: "new" }
end
end
end
# PUT /roles/1
def update
@role.update(role_params)
respond_with @role
@role = Role.find(params[:id])
respond_to do |format|
if @role.update_attributes(params[:role])
format.html { redirect_to @role, notice: 'Role was successfully updated.' }
else
format.html { render action: "edit" }
end
end
end
# DELETE /roles/1
def destroy
@role = Role.find(params[:id])
@role.destroy
respond_with @role
end
private
def role_params
params.require(:role).permit(:description, :name, :members, :slug)
respond_to do |format|
format.html { redirect_to roles_url }
end
end
end

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