├── .env.sample ├── .gitignore ├── .ruby-version ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── Procfile ├── README.md ├── Rakefile ├── app ├── assets │ ├── config │ │ └── manifest.js │ ├── images │ │ └── .keep │ ├── javascripts │ │ ├── application.js │ │ ├── cable.js │ │ ├── channels │ │ │ ├── .keep │ │ │ ├── need.js │ │ │ └── shelter.js │ │ ├── components │ │ │ └── place_autocomplete.js │ │ ├── connect │ │ │ ├── haves.js │ │ │ └── needs.js │ │ ├── notifications.js │ │ └── simple_map.js │ └── stylesheets │ │ ├── application.css │ │ ├── connect │ │ ├── haves.scss │ │ └── needs.scss │ │ ├── main.css │ │ ├── notifications.scss │ │ ├── pages.scss │ │ └── splash.scss ├── channels │ ├── application_cable │ │ ├── channel.rb │ │ └── connection.rb │ ├── need_channel.rb │ └── shelter_channel.rb ├── controllers │ ├── amazon_products_controller.rb │ ├── api │ │ ├── v1 │ │ │ ├── amazon_products_controller.rb │ │ │ ├── charitable_organizations_controller.rb │ │ │ ├── connect │ │ │ │ ├── categories_controller.rb │ │ │ │ ├── flags_controller.rb │ │ │ │ └── markers_controller.rb │ │ │ ├── needs_controller.rb │ │ │ └── shelters_controller.rb │ │ └── v2 │ │ │ └── locations_controller.rb │ ├── application_controller.rb │ ├── charitable_organizations_controller.rb │ ├── concerns │ │ ├── .keep │ │ └── device_identifiable.rb │ ├── connect │ │ └── flagged_markers_controller.rb │ ├── drafts_controller.rb │ ├── location_drafts_controller.rb │ ├── locations_controller.rb │ ├── needs_controller.rb │ ├── organizations_controller.rb │ ├── pages_controller.rb │ ├── shelters_controller.rb │ ├── splash_controller.rb │ └── users_controller.rb ├── helpers │ ├── application_helper.rb │ ├── connect │ │ ├── haves_helper.rb │ │ └── needs_helper.rb │ ├── mucked_homes_helper.rb │ ├── pages_helper.rb │ ├── splash_helper.rb │ └── volunteers_helper.rb ├── importers │ └── api_importer.rb ├── jobs │ ├── application_job.rb │ ├── fetch_amazon_product_job.rb │ ├── import_needs_job.rb │ ├── import_shelters_job.rb │ ├── need_update_notifier_job.rb │ ├── schedule_amazon_fetch_job.rb │ └── shelter_update_notifier_job.rb ├── mailers │ └── application_mailer.rb ├── models │ ├── amazon_product.rb │ ├── application_record.rb │ ├── charitable_organization.rb │ ├── concerns │ │ └── .keep │ ├── connect.rb │ ├── connect │ │ └── marker.rb │ ├── draft.rb │ ├── ignored_amazon_product_need.rb │ ├── location.rb │ ├── location │ │ ├── config.rb │ │ ├── hhrd │ │ │ ├── pois.rb │ │ │ ├── rescuees.rb │ │ │ └── rescuers.rb │ │ └── whitelist.rb │ ├── mucked_home.rb │ ├── need.rb │ ├── page.rb │ ├── shelter.rb │ ├── user.rb │ └── volunteer.rb └── views │ ├── amazon_products │ ├── _form.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ └── show.html.erb │ ├── api │ ├── v1 │ │ ├── amazon_products │ │ │ ├── _amazon_product.json.jbuilder │ │ │ └── index.json.jbuilder │ │ ├── charitable_organizations │ │ │ ├── _charitable_organization.json.jbuilder │ │ │ └── index.json.jbuilder │ │ ├── connect │ │ │ └── markers │ │ │ │ ├── index.json.jbuilder │ │ │ │ └── show.json.jbuilder │ │ ├── needs │ │ │ ├── _need.json.jbuilder │ │ │ └── index.json.jbuilder │ │ └── shelters │ │ │ ├── _shelter.json.jbuilder │ │ │ └── index.json.jbuilder │ └── v2 │ │ └── locations │ │ ├── _location.json.jbuilder │ │ ├── help.json.jbuilder │ │ ├── index.json.jbuilder │ │ └── routes.json.jbuilder │ ├── charitable_organizations │ ├── _form.html.erb │ ├── drafts.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── connect │ └── flagged_markers │ │ ├── index.html.erb │ │ └── show.html.erb │ ├── drafts │ └── show.html.erb │ ├── layouts │ ├── application.html.erb │ ├── locations.html.erb │ ├── mailer.html.erb │ └── mailer.text.erb │ ├── location_drafts │ └── show.html.erb │ ├── locations │ ├── _form.html.erb │ ├── drafts.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── needs │ ├── _form.html.erb │ ├── drafts.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── organizations │ └── show.html.erb │ ├── pages │ ├── _form.html.erb │ ├── _page.html.erb │ ├── edit.html.erb │ └── index.html.erb │ ├── shared │ ├── _drafts_table.html.erb │ ├── _show.html.erb │ └── _table.html.erb │ ├── shelters │ ├── _form.html.erb │ ├── drafts.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── splash │ └── index.html.erb │ └── users │ ├── index.html.erb │ ├── show.html.erb │ └── update.html.erb ├── bin ├── bundle ├── rails ├── rake ├── setup ├── spring ├── update └── yarn ├── config.ru ├── config ├── application.rb ├── boot.rb ├── cable.yml ├── connect_categories.yml ├── database.yml ├── database.yml.travis ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── application_controller_renderer.rb │ ├── assets.rb │ ├── backtrace_silencers.rb │ ├── cookies_serializer.rb │ ├── devise.rb │ ├── filter_parameter_logging.rb │ ├── geocoder.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── simple_form.rb │ ├── traffic_cop.rb │ └── wrap_parameters.rb ├── locales │ ├── devise.en.yml │ ├── en.yml │ └── simple_form.en.yml ├── puma.rb ├── routes.rb ├── secrets.yml └── spring.rb ├── db ├── migrate │ ├── 20170831193310_create_shelters.rb │ ├── 20170831193314_create_needs.rb │ ├── 20170831220720_change_lat_long_to_floats.rb │ ├── 20170901185804_add_update_draft_table.rb │ ├── 20170901194923_devise_create_users.rb │ ├── 20170901201514_create_amazon_products.rb │ ├── 20170901224459_add_accept_deny_draft.rb │ ├── 20170902123713_add_disabled_to_amazon_products.rb │ ├── 20170902140452_create_ignored_amazon_product_needs.rb │ ├── 20170902203116_add_archive_to_need.rb │ ├── 20170902213139_create_mucked_homes.rb │ ├── 20170902222739_create_volunteers.rb │ ├── 20170903113333_create_connect_markers.rb │ ├── 20170903230413_create_charitable_organizations.rb │ ├── 20170903231428_add_archive_to_charitable_organizations.rb │ ├── 20170904025322_add_email_to_connect_markers.rb │ ├── 20170904165336_add_product_categories_to_amazon_products.rb │ ├── 20170905114546_add_data_to_markers.rb │ ├── 20170905201043_create_pages.rb │ ├── 20170906160409_add_amazon_price_to_products.rb │ ├── 20170907032253_add_fields_to_shelter.rb │ ├── 20170907070934_add_location_table.rb │ ├── 20170907152426_add_device_uuid_connect_markers.rb │ ├── 20170908152859_update_category_on_connect_markers.rb │ ├── 20170911052811_add_state_to_shelter.rb │ ├── 20170911205637_add_indexes.rb │ ├── 20170911210028_add_calculated_values_for_shelters.rb │ └── 20170920210424_add_index_to_data_on_connect_markers.rb ├── schema.rb ├── seeds.rb └── seeds │ ├── amazon_products.json │ └── ignored_amazon_product_needs.json ├── lib ├── assets │ └── .keep ├── tasks │ ├── .keep │ ├── amazon.rake │ ├── data.rake │ └── import.rake └── templates │ └── erb │ └── scaffold │ └── _form.html.erb ├── log └── .keep ├── package.json ├── public ├── 404.html ├── 422.html ├── 500.html ├── api-docs │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── index.html │ ├── oauth2-redirect.html │ ├── swagger-ui-bundle.js │ ├── swagger-ui-bundle.js.map │ ├── swagger-ui-standalone-preset.js │ ├── swagger-ui-standalone-preset.js.map │ ├── swagger-ui.css │ ├── swagger-ui.css.map │ ├── swagger-ui.js │ ├── swagger-ui.js.map │ ├── swagger-v1.json │ └── swagger-v2.json ├── apple-touch-icon-precomposed.png ├── apple-touch-icon.png ├── contributors.html ├── favicon.ico ├── images │ └── readme │ │ ├── screenshot_create-service-account-key.png │ │ ├── screenshot_enable_google_sheets_api.png │ │ └── screenshot_rails_server_run_test.png └── robots.txt ├── test ├── application_system_test_case.rb ├── controllers │ ├── .keep │ ├── amazon_products_controller_test.rb │ ├── api │ │ └── v1 │ │ │ ├── amazon_product_needs_controller_test.rb │ │ │ ├── charitable_organizations_controller_test.rb │ │ │ ├── connect │ │ │ ├── categories_controller_test.rb │ │ │ ├── flags_controller_test.rb │ │ │ └── markers_controller_test.rb │ │ │ ├── needs_controller_test.rb │ │ │ └── shelters_controller_test.rb │ ├── charitable_organizations_controller_test.rb │ ├── connect │ │ └── flagged_markers_controller_test.rb │ ├── drafts_controller_test.rb │ ├── location_drafts_controller_test.rb │ ├── locations_controller_test.rb │ ├── needs_controller_test.rb │ ├── pages_controller_test.rb │ └── shelters_controller_test.rb ├── fixtures │ ├── .keep │ ├── amazon_products.yml │ ├── charitable_organizations.yml │ ├── connect │ │ └── markers.yml │ ├── drafts.yml │ ├── files │ │ └── .keep │ ├── locations.yml │ ├── mucked_homes.yml │ ├── needs.yml │ ├── pages.yml │ ├── shelters.yml │ ├── users.yml │ └── volunteers.yml ├── helpers │ └── .keep ├── integration │ └── .keep ├── jobs │ ├── fetch_amazon_product_job_test.rb │ ├── import_needs_job_test.rb │ ├── import_sheet_data_job_test.rb │ ├── import_shelters_job_test.rb │ └── schedule_amazon_fetch_job_test.rb ├── mailers │ └── .keep ├── models │ ├── .keep │ ├── amazon_product_test.rb │ ├── charitable_organization_test.rb │ ├── connect │ │ └── marker_test.rb │ ├── ignored_amazon_product_need_test.rb │ ├── location_test.rb │ ├── mucked_home_test.rb │ ├── need_test.rb │ ├── page_test.rb │ ├── shelter_test.rb │ ├── user_test.rb │ └── volunteer_test.rb ├── system │ ├── .keep │ ├── admin_searchings_test.rb │ └── homepage_test.rb ├── test_helper.rb └── vcr_cassettes │ ├── amazon-missing.yml │ ├── amazon.yml │ ├── needs.yml │ └── shelters.yml ├── tmp └── .keep └── vendor └── .keep /.env.sample: -------------------------------------------------------------------------------- 1 | AWS_ACCESS_KEY_ID="AKIAJ5PESCDQX7KIMQ5Q" 2 | AWS_SECRET_ACCESS_KEY="" 3 | AWS_ASSOCIATE_TAG=oneclickrelie-20 4 | GOOGLE_GEOCODER_API_KEY="" 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore all logfiles and tempfiles. 11 | /log/* 12 | /tmp/* 13 | !/log/.keep 14 | !/tmp/.keep 15 | 16 | /node_modules 17 | /yarn-error.log 18 | 19 | .byebug_history 20 | .env 21 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.4.1 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | cache: bundler 3 | rvm: 4 | - 2.4.1 5 | addons: 6 | postgresql: '9.6' 7 | sources: 8 | - google-chrome 9 | apt: 10 | packages: 11 | - google-chrome-stable 12 | services: 13 | - redis-server 14 | before_script: 15 | - psql -c 'create database travis_ci_test;' -U postgres 16 | - cp config/database.yml.travis config/database.yml 17 | - wget http://chromedriver.storage.googleapis.com/2.27/chromedriver_linux64.zip 18 | - unzip chromedriver_linux64.zip 19 | - sudo apt-get install libnss3 20 | - sudo apt-get --only-upgrade install google-chrome-stable 21 | - sudo cp chromedriver /usr/local/bin/. 22 | - sudo chmod +x /usr/local/bin/chromedriver 23 | - export DISPLAY=:99.0 24 | - sh -e /etc/init.d/xvfb start 25 | - sleep 3 26 | script: 27 | - RAILS_ENV=test bundle exec rails db:migrate --trace 28 | - bundle exec rails db:test:prepare 29 | - bundle exec rails test 30 | - bundle exec rails test:system 31 | deploy: 32 | - provider: heroku 33 | api_key: 34 | secure: jheoABY2Yhe+eP4DB87h877u4cSc02Rf09PhmRxNroQQHv3XkToVgxXo33TEEuCoucDfhSepOeky4QozarJ7hSHCn1ssPb8jo3klicxPrB90t8SBPHB7evqfcaXAGYZBIPcvoGXzqQ0Brv/IvSP2eK81KUFAA8CAE9jUI4HXJkqRWnL2SC51yytxhnTBruOlTA3Z/90vgj9q6y3Y+xZCP3DrBDoBlvdaeyOXt54X+vcj+ZKepiMTdOuSEkC8dxuLiru7yMWZPANvvP/B/MLnh6XdG/EggRujR/uKvfrRKjKZjRt/TkMM7SarP+klGqOiaHV9KOct28E2Wbmoe03Qllk2NopqsanF4wemUWb8jCp4fLaf6e6KPnzA+Vfr3C8h1AyJYAXDXKx+jAa3pGDSSuDQmvO9lNtpLpxNbVwHSpBvdaY9MDta64oj+5eb2RR/UZZmB8JBuW2+2B22cf/OPU/Z915qWzshE3Fi0pTEgca4Tq37KqzyuYl8n4JnLxsUIWYVytWMMX8JtnvMYJdVLJEWrNidAD/BrZQGRhKUE8vnTMK7sFCzC2XInNpFXXDW0z2Keor8tb0Qk0y+PUyUlwy6YJgmITGkBHcRNWM0tYwO8+DS/duqvlSg0gMdxE6sa6mz9eVk1oP7KBJ/O4VdvJoRkdMiMKC9UvCceLqAT5A= 35 | app: harvey-api 36 | on: 37 | repo: sketch-city/harvey-api 38 | run: 39 | - "rails db:migrate" 40 | - "rails calculate_values" 41 | - "rake cleanup" 42 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | ruby "2.4.1" 4 | 5 | git_source(:github) do |repo_name| 6 | repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") 7 | "https://github.com/#{repo_name}.git" 8 | end 9 | 10 | gem 'rails', '~> 5.1.1' 11 | gem 'pg', '~> 0.18' 12 | gem 'puma', '~> 3.7' 13 | gem 'sass-rails', '~> 5.0' 14 | gem 'uglifier', '>= 1.3.0' 15 | gem 'jbuilder', '~> 2.5' 16 | gem 'google-api-client', '~> 0.11' 17 | gem 'sucker_punch' 18 | gem 'activejob-traffic_control' 19 | gem 'dotenv-rails' 20 | gem 'rack-cors', :require => 'rack/cors' 21 | gem 'geocoder' 22 | gem 'devise' 23 | gem 'vacuum' 24 | gem 'connection_pool' 25 | gem "httparty", "~> 0.15.6" 26 | gem 'redis', '~> 3.2' 27 | gem 'simple_form' 28 | gem 'redcarpet' 29 | 30 | group :development, :test do 31 | gem 'capybara', '~> 2.13' 32 | gem 'selenium-webdriver' 33 | gem 'pry' 34 | gem 'vcr' 35 | gem "webmock", "~> 3.0" 36 | end 37 | 38 | group :development do 39 | gem 'web-console', '>= 3.3.0' 40 | gem 'listen', '>= 3.0.5', '< 3.2' 41 | gem 'spring' 42 | gem 'spring-watcher-listen', '~> 2.0.0' 43 | end 44 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: bundle exec puma -C config/puma.rb 2 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative 'config/application' 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../javascripts .js 3 | //= link_directory ../stylesheets .css 4 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sketch-city/harvey-api/00b8d9ce005a69389b665cb66c9999f39fe046d8/app/assets/images/.keep -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | //= require rails-ujs 2 | //= require_tree . 3 | //= require_tree ./components 4 | -------------------------------------------------------------------------------- /app/assets/javascripts/cable.js: -------------------------------------------------------------------------------- 1 | //= require action_cable 2 | //= require_self 3 | //= require_tree ./channels 4 | 5 | ;(function() { 6 | this.App || (this.App = {}) 7 | 8 | App.cable = ActionCable.createConsumer() 9 | }.call(this)) 10 | -------------------------------------------------------------------------------- /app/assets/javascripts/channels/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sketch-city/harvey-api/00b8d9ce005a69389b665cb66c9999f39fe046d8/app/assets/javascripts/channels/.keep -------------------------------------------------------------------------------- /app/assets/javascripts/channels/need.js: -------------------------------------------------------------------------------- 1 | App.need = App.cable.subscriptions.create("NeedChannel", { 2 | connected: function() {}, 3 | received: function(data) { 4 | App.updatedNeeds.add(data.need) 5 | } 6 | }) 7 | -------------------------------------------------------------------------------- /app/assets/javascripts/channels/shelter.js: -------------------------------------------------------------------------------- 1 | App.shelter = App.cable.subscriptions.create("ShelterChannel", { 2 | connected: function() {}, 3 | received: function(data) { 4 | App.updatedShelters.add(data.shelter) 5 | } 6 | }) 7 | -------------------------------------------------------------------------------- /app/assets/javascripts/connect/haves.js: -------------------------------------------------------------------------------- 1 | // Place all the behaviors and hooks related to the matching controller here. 2 | // All this logic will automatically be available in application.js. 3 | -------------------------------------------------------------------------------- /app/assets/javascripts/connect/needs.js: -------------------------------------------------------------------------------- 1 | // Place all the behaviors and hooks related to the matching controller here. 2 | // All this logic will automatically be available in application.js. 3 | -------------------------------------------------------------------------------- /app/assets/javascripts/notifications.js: -------------------------------------------------------------------------------- 1 | function SubscribableArray() { 2 | return { 3 | _items: [], 4 | _callbacks: [], 5 | clear: function() { 6 | this._items = [] 7 | this._publish() 8 | }, 9 | add: function(shelter) { 10 | this._items.push(shelter) 11 | this._publish() 12 | }, 13 | subscribe: function(callback) { 14 | this._callbacks.push(callback) 15 | }, 16 | _publish: function() { 17 | const shelters = this._items 18 | this._callbacks.forEach(function(cb) { 19 | cb(shelters) 20 | }) 21 | } 22 | } 23 | } 24 | 25 | ;(function() { 26 | this.App || (this.App = {}) 27 | 28 | App.updatedShelters = new SubscribableArray() 29 | App.updatedNeeds = new SubscribableArray() 30 | }.call(this)) 31 | -------------------------------------------------------------------------------- /app/assets/javascripts/simple_map.js: -------------------------------------------------------------------------------- 1 | function simpleMap(options) { 2 | var selector = options.selector 3 | var name = options.name || "Location" 4 | var lat = options.lat 5 | var lng = options.lng 6 | 7 | var element = document.querySelector(selector) 8 | if (!!element) { 9 | var map = new google.maps.Map(element, { 10 | zoom: 12, 11 | center: { lat: lat, lng: lng } 12 | }) 13 | 14 | var marker = new google.maps.Marker({ 15 | position: { lat: lat, lng: lng }, 16 | map: map, 17 | title: name 18 | }) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's 6 | * vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS 10 | * files in this directory. Styles in this file should be added after the last require_* statement. 11 | * It is generally better to create a new file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /app/assets/stylesheets/connect/haves.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the connect/haves controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/connect/needs.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the connect/needs controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/notifications.scss: -------------------------------------------------------------------------------- 1 | .new-record-notification { 2 | text-align: right; 3 | } 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/pages.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the pages controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/splash.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the splash controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Channel < ActionCable::Channel::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Connection < ActionCable::Connection::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/channels/need_channel.rb: -------------------------------------------------------------------------------- 1 | class NeedChannel < ApplicationCable::Channel 2 | def subscribed 3 | stream_for "needs" 4 | end 5 | 6 | def unsubscribed 7 | # Any cleanup needed when channel is unsubscribed 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/channels/shelter_channel.rb: -------------------------------------------------------------------------------- 1 | class ShelterChannel < ApplicationCable::Channel 2 | def subscribed 3 | stream_for "shelters" 4 | end 5 | 6 | def unsubscribed 7 | # Any cleanup needed when channel is unsubscribed 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/controllers/amazon_products_controller.rb: -------------------------------------------------------------------------------- 1 | class AmazonProductsController < ApplicationController 2 | before_action :authenticate_admin! 3 | before_action :set_headers 4 | 5 | def index 6 | @amazon_products = AmazonProduct.all 7 | end 8 | 9 | def show 10 | @amazon_product = AmazonProduct.find params[:id] 11 | end 12 | 13 | def edit 14 | @amazon_product = AmazonProduct.find params[:id] 15 | end 16 | 17 | def update 18 | @amazon_product = AmazonProduct.find params[:id] 19 | if @amazon_product.update amazon_product_params 20 | redirect_to @amazon_product, notice: 'Shelter was successfully created.' 21 | else 22 | render :edit 23 | end 24 | end 25 | 26 | private 27 | def set_headers 28 | @columns = AmazonProduct::ColumnNames 29 | @headers = AmazonProduct::HeaderNames 30 | end 31 | 32 | def amazon_product_params 33 | params.require(:amazon_product).permit(AmazonProduct::UpdateFields).keep_if { |_,v| v.present? } 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /app/controllers/api/v1/amazon_products_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::V1::AmazonProductsController < ApplicationController 2 | 3 | before_action do 4 | request.format = :json 5 | end 6 | 7 | def index 8 | @filters = {} 9 | # get all needs into a nice array 10 | # find all Amazon products we have 11 | @needs = Need.all.map(&:clean_needs).flatten.uniq 12 | 13 | if params[:need].present? 14 | @filters[:need] = params[:need] 15 | @needs = @needs.select{|need| need =~ /#{params[:need]}/i } 16 | end 17 | 18 | @products = AmazonProduct 19 | .active 20 | .where(need: @needs) 21 | .order("priority, need") 22 | 23 | if params[:priority].to_s == "true" 24 | @filters[:priority] = params[:priority] 25 | @products = @products.priority 26 | end 27 | 28 | if params[:category].present? 29 | @filters[:category] = params[:category] 30 | @products = @products 31 | .where("category_specific ILIKE ?", "%#{params[:category]}%") 32 | .or(@products.where("category_general ILIKE ?", "%#{params[:category]}%")) 33 | end 34 | 35 | if params[:limit].to_i > 0 36 | @filters[:limit] = params[:limit].to_i 37 | @products = @products.limit(params[:limit].to_i) 38 | end 39 | 40 | fresh_when(etag: @products, last_modified: @products.maximum(:updated_at), public: true) 41 | 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /app/controllers/api/v1/charitable_organizations_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::V1::CharitableOrganizationsController < ApplicationController 2 | 3 | before_action do 4 | request.format = :json 5 | end 6 | 7 | def index 8 | @filters = {} 9 | # get all charitable_organizations into a nice array 10 | # find all Amazon products we have 11 | @charitable_organizations = CharitableOrganization.all 12 | 13 | if params[:services].present? 14 | @filters[:services] = params[:services] 15 | @charitable_organizations = @charitable_organizations.where("services ILIKE ?", "%#{params[:services]}%") 16 | end 17 | 18 | if params[:name].present? 19 | @filters[:name] = params[:name] 20 | @charitable_organizations = @charitable_organizations.where("name ILIKE ?", "%#{params[:name]}%") 21 | end 22 | 23 | if params[:food_bank].present? 24 | @filters[:food_bank] = params[:food_bank] 25 | @charitable_organizations = @charitable_organizations.where(food_bank: true) 26 | end 27 | 28 | if params[:city].present? 29 | @filters[:city] = params[:city] 30 | @charitable_organizations = @charitable_organizations.where("city ILIKE ?", "%#{params[:city]}%") 31 | end 32 | 33 | if stale?(etag: @charitable_organizations, last_modified: @charitable_organizations.maximum(:updated_at), public: true) 34 | 35 | # here because limit is causing a SQL problem: column "distance" does not exist 36 | if params[:limit].to_i > 0 37 | @filters[:limit] = params[:limit].to_i 38 | @charitable_organizations = @charitable_organizations.take(params[:limit].to_i) 39 | end 40 | 41 | end 42 | 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /app/controllers/api/v1/connect/categories_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | module Connect 6 | class CategoriesController < ApplicationController 7 | def index 8 | render json: categories 9 | end 10 | 11 | private 12 | 13 | def categories 14 | @categories ||= Rails.application.config_for(:connect_categories) 15 | end 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /app/controllers/api/v1/connect/flags_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | module Connect 6 | class FlagsController < ApplicationController 7 | include DeviceIdentifiable 8 | 9 | def create 10 | @marker = ::Connect::Marker.find(params[:marker_id]) 11 | @marker.flag_as_inappropriate!(device_uuid: device_uuid, reason: params[:reason]) 12 | head :no_content 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/controllers/api/v1/needs_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::V1::NeedsController < ApplicationController 2 | 3 | before_action do 4 | request.format = :json 5 | end 6 | 7 | def index 8 | @filters = {} 9 | @needs = Need.all 10 | 11 | if params[:lat].present? && params[:lon].present? 12 | @filters[:lon] = params[:lon] 13 | @filters[:lat] = params[:lat] 14 | @needs = @needs.near([params[:lat], params[:lon]], 100) 15 | end 16 | 17 | if params[:location_name].present? 18 | @filters[:location_name] = params[:location_name] 19 | @needs = @needs.where("location_name ILIKE ?", "%#{params[:location_name]}%") 20 | end 21 | 22 | if params[:volunteers_needed].present? 23 | @filters[:volunteers_needed] = params[:volunteers_needed] 24 | @needs = @needs.where(are_volunteers_needed: true) 25 | end 26 | 27 | if params[:supplies_needed].present? 28 | @filters[:supplies_needed] = params[:supplies_needed] 29 | @needs = @needs.where(are_supplies_needed: true) 30 | end 31 | 32 | 33 | if stale?(etag: @needs, last_modified: @needs.maximum(:updated_at), public: true) 34 | 35 | # here because limit is causing a SQL problem: column "distance" does not exist 36 | if params[:limit].to_i > 0 37 | @filters[:limit] = params[:limit].to_i 38 | @needs = @needs.take(params[:limit].to_i) 39 | end 40 | 41 | end 42 | 43 | end 44 | 45 | end 46 | -------------------------------------------------------------------------------- /app/controllers/api/v1/shelters_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::V1::SheltersController < ApplicationController 2 | 3 | before_action do 4 | request.format = :json 5 | end 6 | 7 | def index 8 | @filters = {} 9 | @shelters = Shelter.all 10 | 11 | if params[:lat].present? && params[:lon].present? 12 | @filters[:lon] = params[:lon] 13 | @filters[:lat] = params[:lat] 14 | @shelters = @shelters.near([params[:lat], params[:lon]], 100, order: "distance") 15 | end 16 | 17 | if params[:county].present? 18 | @filters[:county] = params[:county] 19 | @shelters = @shelters.where("county ILIKE ?", "%#{@filters[:county]}%") 20 | end 21 | 22 | if params[:shelter].present? 23 | @filters[:shelter] = params[:shelter] 24 | @shelters = @shelters.where("shelter ILIKE ?", "%#{@filters[:shelter]}%") 25 | end 26 | 27 | if params[:accepting].present? 28 | @filters[:accepting] = params[:accepting] 29 | @shelters = @shelters.where(accepting: true) 30 | end 31 | 32 | if stale?(etag: @shelters, last_modified: @shelters.maximum(:updated_at), public: true) 33 | 34 | # here because limit is causing a SQL problem: column "distance" does not exist 35 | if params[:limit].to_i > 0 36 | @filters[:limit] = params[:limit].to_i 37 | @shelters = @shelters.take(params[:limit].to_i) 38 | end 39 | 40 | end 41 | end 42 | 43 | end 44 | -------------------------------------------------------------------------------- /app/controllers/api/v2/locations_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::V2::LocationsController < ApplicationController 2 | before_action :setup, except: [:routes] 3 | 4 | before_action do 5 | request.format = :json 6 | end 7 | 8 | def setup 9 | @organization = params[:organization] 10 | @legacy_table_name = params[:legacy_table_name] 11 | @location_class ||= Location::Whitelist.find(@organization, @legacy_table_name) 12 | @locations ||= Location::Whitelist.find(@organization, @legacy_table_name).all 13 | end 14 | 15 | def index 16 | 17 | @filters = {} 18 | 19 | @locations.filters.values.each do |filter| 20 | case filter.type 21 | when :coordinates 22 | if params[:lat].present? && params[:lon].present? 23 | @filters[:lon] = params[:lon] 24 | @filters[:lat] = params[:lat] 25 | @locations = @locations.near([params[:lat], params[:lon]], 100) 26 | end 27 | when :limit 28 | if params[:limit].to_i > 0 29 | @locations = @locations.limit(params[:limit].to_i) 30 | end 31 | when :truthy 32 | if params[filter.name].present? 33 | @filters[filter.name] = params[filter.name] 34 | 35 | if(filter.column) 36 | @locations = @locations.where(filter.name => true) 37 | else 38 | @locations = @locations.where("(legacy_data->>?)::boolean", filter.name) 39 | end 40 | end 41 | else 42 | if params[filter.name].present? 43 | @filters[filter.name] = params[filter.name] 44 | 45 | # Location whitelists valid columns. No sql injection here. 46 | if(filter.column) 47 | @locations = @locations.where("#{filter.name} ILIKE ?", "%#{@filters[filter.name]}%") 48 | else 49 | @locations = @locations.where("legacy_data->>? ILIKE ?", filter.name, "%#{@filters[filter.name]}%") 50 | end 51 | end 52 | end 53 | end 54 | 55 | def help 56 | end 57 | 58 | def routes 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery with: :null_session 3 | 4 | before_action do 5 | @application_name = ENV.fetch('CANONICAL_NAME', 'Disaster API') 6 | end 7 | 8 | def admin? 9 | user_signed_in? && current_user.admin? 10 | end 11 | 12 | def authenticate_admin! 13 | if !admin? 14 | redirect_to request.referrer || root_path, notice: "Admins Only! :|" 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/controllers/charitable_organizations_controller.rb: -------------------------------------------------------------------------------- 1 | class CharitableOrganizationsController < ApplicationController 2 | before_action :set_headers 3 | before_action :set_charitable_organization, only: [:show, :edit, :update, :destroy, :archive] 4 | 5 | def index 6 | @charitable_organizations = CharitableOrganization.all 7 | end 8 | 9 | def new 10 | @charitable_organization = CharitableOrganization.new 11 | end 12 | 13 | def create 14 | 15 | if(user_signed_in? && current_user.admin?) 16 | @charitable_organization = CharitableOrganization.new(charitable_organization_update_params) 17 | 18 | if @charitable_organization.save 19 | redirect_to @charitable_organization, notice: 'Charitable Organization was successfully created.' 20 | else 21 | render :new 22 | end 23 | else 24 | draft = Draft.new(info: charitable_organization_update_params.merge({record_type: CharitableOrganization.name})) 25 | 26 | if draft.save 27 | redirect_to draft, notice: 'Your new Charitable Organization is pending approval.' 28 | else 29 | @charitable_organization = CharitableOrganization.new(charitable_organization_update_params) 30 | render :new 31 | end 32 | end 33 | end 34 | 35 | def show 36 | @charitable_organization = CharitableOrganization.find(params[:id]) 37 | end 38 | 39 | def destroy 40 | end 41 | 42 | def archive 43 | if(user_signed_in? && current_user.admin?) 44 | @charitable_organization.update_attributes(active: false) 45 | redirect_to charitable_organizations_path, notice: "Archived!" 46 | else 47 | redirect_to charitable_organizations_path, notice: "You must be an admin to archive." 48 | end 49 | end 50 | 51 | def edit 52 | end 53 | 54 | def update 55 | if(user_signed_in? && current_user.admin?) 56 | if @charitable_organization.update(charitable_organization_update_params) 57 | redirect_to @charitable_organization, notice: 'Charitable Organization was successfully updated.' 58 | else 59 | render :edit 60 | end 61 | else 62 | draft = Draft.new(record: @charitable_organization, info: charitable_organization_update_params) 63 | 64 | if draft.save 65 | redirect_to draft, notice: 'Your Charitable Organization update is pending approval.' 66 | else 67 | render :edit 68 | end 69 | end 70 | end 71 | 72 | 73 | def drafts 74 | @drafts = Draft.includes(:record).where("record_type = ? OR info->>'record_type' = 'CharitableOrganization'", CharitableOrganization.name).where(accepted_by_id: nil).where(denied_by_id: nil) 75 | end 76 | 77 | def set_headers 78 | @columns = CharitableOrganization::ColumnNames 79 | @headers = CharitableOrganization::HeaderNames 80 | end 81 | 82 | def set_charitable_organization 83 | @charitable_organization = CharitableOrganization.find(params[:id]) 84 | end 85 | 86 | def charitable_organization_update_params 87 | params.require(:charitable_organization).permit(CharitableOrganization::UpdateFields).keep_if { |_,v| v.present? } 88 | end 89 | 90 | end 91 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sketch-city/harvey-api/00b8d9ce005a69389b665cb66c9999f39fe046d8/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /app/controllers/concerns/device_identifiable.rb: -------------------------------------------------------------------------------- 1 | module DeviceIdentifiable 2 | extend ActiveSupport::Concern 3 | 4 | included do 5 | before_action :check_device_uuid, only: [:create, :update] 6 | end 7 | 8 | private 9 | 10 | def device_uuid 11 | request.headers['HTTP_DISASTERCONNECT_DEVICE_UUID'] 12 | end 13 | 14 | def missing_device_uuid 15 | render(json: { device_uuid: ['Must be set with DisasterConnect-Device-UUID header'] }, status: :forbidden) 16 | end 17 | 18 | def check_device_uuid 19 | missing_device_uuid if device_uuid.blank? 20 | end 21 | end -------------------------------------------------------------------------------- /app/controllers/connect/flagged_markers_controller.rb: -------------------------------------------------------------------------------- 1 | class Connect::FlaggedMarkersController < ApplicationController 2 | before_action :authenticate_admin! 3 | helper_method :fields 4 | 5 | def index 6 | logger.info current_user 7 | @flagged_markers = ::Connect::Marker.unresolved.flagged 8 | end 9 | 10 | def show 11 | @flagged_marker = ::Connect::Marker.find(params[:id]) 12 | end 13 | 14 | def update 15 | ::Connect::Marker.find(params[:id]).update!(resolved: true) 16 | logger.info "#{current_user.email} confirmed marker[#{params[:id]}] as inappropriate." 17 | redirect_to connect_flagged_markers_url, notice: 'Marker confirmed.' 18 | end 19 | 20 | def destroy 21 | ::Connect::Marker.find(params[:id]).clear_inappropriate_flag! 22 | logger.info "#{current_user.email} cleared marker[#{params[:id]}]." 23 | redirect_to connect_flagged_markers_url, notice: 'Marker cleared.' 24 | end 25 | 26 | private 27 | 28 | def fields 29 | %w(flagged_at flagged_for marker_type name address) 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /app/controllers/drafts_controller.rb: -------------------------------------------------------------------------------- 1 | class DraftsController < ApplicationController 2 | before_action :authenticate_admin!, only: [:destroy, :accept] 3 | before_action :set_record 4 | 5 | def show 6 | @columns = @record.class::ColumnNames 7 | @headers = @record.class::HeaderNames 8 | end 9 | 10 | def destroy 11 | @draft.update(denied_by: current_user) 12 | redirect_to @draft.record || root_path, notice: "#{@record.class.name} update was denied." 13 | end 14 | 15 | def accept 16 | info = @draft.info.delete_if { |k,_| "record_type" == k } 17 | 18 | @record.assign_attributes(info) 19 | 20 | if(@record.save) 21 | @draft.update(record: @record, accepted_by: current_user) 22 | redirect_to [:drafts, @record.class.name.underscore.pluralize.to_sym], notice: "#{@record.class.name} updated" 23 | else 24 | flash[:notice] = "Something went wrong." 25 | render :edit 26 | end 27 | end 28 | 29 | private 30 | 31 | def set_record 32 | @draft = Draft.find(params[:id]) 33 | if(@draft.record) 34 | @record = @draft.record 35 | else 36 | @record = @draft.info["record_type"].constantize.new 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /app/controllers/location_drafts_controller.rb: -------------------------------------------------------------------------------- 1 | class LocationDraftsController < ApplicationController 2 | before_action :authenticate_admin!, only: [:destroy, :accept] 3 | before_action :set_record 4 | 5 | layout "locations" 6 | 7 | def show 8 | @columns = @record.class.table_columns 9 | @headers = @record.class.table_headers 10 | end 11 | 12 | def destroy 13 | @draft.update(denied_by: current_user) 14 | redirect_after_update("Update was denied.") 15 | end 16 | 17 | def accept 18 | info = @draft.info 19 | @record.assign_attributes(info) 20 | 21 | if(@record.save) 22 | @draft.update(record: @record, accepted_by: current_user) 23 | redirect_after_update("#{@record.class.legacy_table_display_name.singularize} updated") 24 | else 25 | flash[:notice] = "Something went wrong." 26 | render :edit 27 | end 28 | end 29 | 30 | private 31 | 32 | def set_record 33 | @draft = Draft.find(params[:id]) 34 | @organization = @draft.info['organization'] 35 | @legacy_table_name = @draft.info['legacy_table_name'] 36 | if(@draft.record) 37 | @record = Location::Whitelist.find(@organization, @legacy_table_name).find(@draft.record_id) 38 | else 39 | @record = Location::Whitelist.find(@organization, @legacy_table_name).new 40 | end 41 | end 42 | 43 | def next_draft 44 | @next_draft ||= Draft. 45 | where("info->>'organization' = ?", @organization). 46 | where("info->>'legacy_table_name' = ?", @legacy_table_name). 47 | where(accepted_by_id: nil). 48 | where(denied_by_id: nil). 49 | first 50 | end 51 | 52 | def redirect_after_update(msg) 53 | if(next_draft.present?) 54 | path = location_draft_path(organization: @organization, legacy_table_name: @legacy_table_name, id: @next_draft.id) 55 | msg = msg+" Redirecting to next draft in queue." 56 | else 57 | path = locations_path(organization: @organization, legacy_table_name: @legacy_table_name) 58 | msg = msg+" All drafts processed. Keep up the good work and thank you." 59 | end 60 | 61 | redirect_to path, notice: msg 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /app/controllers/needs_controller.rb: -------------------------------------------------------------------------------- 1 | class NeedsController < ApplicationController 2 | before_action :set_headers 3 | before_action :set_need, only: [:show, :edit, :update, :destroy, :archive] 4 | 5 | def index 6 | @needs = Need.all 7 | end 8 | 9 | def new 10 | @need = Need.new 11 | end 12 | 13 | def create 14 | 15 | if(user_signed_in? && current_user.admin?) 16 | @need = Need.new(need_update_params) 17 | 18 | if @need.save 19 | redirect_to @need, notice: 'Need was successfully created.' 20 | else 21 | render :new 22 | end 23 | else 24 | draft = Draft.new(info: need_update_params.merge({record_type: Need.name})) 25 | 26 | if draft.save 27 | redirect_to draft, notice: 'Your new need is pending approval.' 28 | else 29 | @need = Need.new(need_update_params) 30 | render :new 31 | end 32 | end 33 | end 34 | 35 | def show 36 | @need = Need.find(params[:id]) 37 | end 38 | 39 | def destroy 40 | end 41 | 42 | def archive 43 | if(user_signed_in? && current_user.admin?) 44 | @need.update_attributes(active: false) 45 | redirect_to needs_path, notice: "Archived!" 46 | else 47 | redirect_to needs_path, notice: "You must be an admin to archive." 48 | end 49 | end 50 | 51 | def edit 52 | end 53 | 54 | def update 55 | if(user_signed_in? && current_user.admin?) 56 | if @need.update(need_update_params) 57 | redirect_to @need, notice: 'Need was successfully updated.' 58 | else 59 | render :edit 60 | end 61 | else 62 | draft = Draft.new(record: @need, info: need_update_params) 63 | 64 | if draft.save 65 | redirect_to draft, notice: 'Your need update is pending approval.' 66 | else 67 | render :edit 68 | end 69 | end 70 | end 71 | 72 | 73 | def drafts 74 | @drafts = Draft.includes(:record).where("record_type = ? OR info->>'record_type' = 'Need'", Need.name).where(accepted_by_id: nil).where(denied_by_id: nil) 75 | end 76 | 77 | def set_headers 78 | @columns = Need::ColumnNames 79 | @headers = Need::HeaderNames 80 | end 81 | 82 | def set_need 83 | @need = Need.find(params[:id]) 84 | end 85 | 86 | def need_update_params 87 | params.require(:need).permit(Need::UpdateFields).keep_if { |_,v| v.present? } 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /app/controllers/organizations_controller.rb: -------------------------------------------------------------------------------- 1 | class OrganizationsController < ApplicationController 2 | 3 | layout "locations" 4 | 5 | def show 6 | @organization = params[:organization] 7 | @organization_tables = Location::Whitelist.organization_tables(@organization) 8 | if !@organization_tables.present? 9 | redirect_to root_path, notice: "Unable to find organization." 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/controllers/pages_controller.rb: -------------------------------------------------------------------------------- 1 | class PagesController < ApplicationController 2 | 3 | def index 4 | if(user_signed_in? && current_user.admin?) 5 | @pages = Page.all 6 | else 7 | redirect_to root_path 8 | end 9 | end 10 | 11 | def edit 12 | if(user_signed_in? && current_user.admin?) 13 | @page = Page.find(params[:id]) 14 | else 15 | redirect_to root_path 16 | end 17 | end 18 | 19 | def update 20 | if(user_signed_in? && current_user.admin?) 21 | @page = Page.find(params[:id]) 22 | if @page.update(page_params) 23 | redirect_to root_path, notice: 'Page was successfully updated.' 24 | end 25 | else 26 | redirect_to root_path 27 | end 28 | end 29 | 30 | private 31 | 32 | def page_params 33 | params.require(:page).permit(:key, :content) 34 | end 35 | 36 | end 37 | -------------------------------------------------------------------------------- /app/controllers/shelters_controller.rb: -------------------------------------------------------------------------------- 1 | class SheltersController < ApplicationController 2 | before_action :set_headers 3 | before_action :set_shelter, only: [:show, :edit, :update, :destroy, :archive] 4 | 5 | def index 6 | @shelters = Shelter.all 7 | @page = Page.shelters.first_or_initialize 8 | 9 | end 10 | 11 | def new 12 | @shelter = Shelter.new 13 | end 14 | 15 | def create 16 | if(admin?) 17 | @shelter = Shelter.new(shelter_update_params) 18 | 19 | if @shelter.save 20 | redirect_to @shelter, notice: 'Shelter was successfully created.' 21 | else 22 | render :new 23 | end 24 | else 25 | draft = Draft.new(info: shelter_update_params.merge({record_type: Shelter.name})) 26 | 27 | if draft.save 28 | redirect_to draft, notice: 'Your new shelter is pending approval.' 29 | else 30 | @shelter = Shelter.new(shelter_update_params) 31 | render :new 32 | end 33 | end 34 | end 35 | 36 | def show 37 | end 38 | 39 | def edit 40 | end 41 | 42 | def update 43 | if(admin?) 44 | if @shelter.update(shelter_update_params) 45 | redirect_to @shelter, notice: 'Shelter was successfully updated.' 46 | else 47 | render :edit 48 | end 49 | else 50 | draft = Draft.new(record: @shelter, info: shelter_update_params) 51 | 52 | if draft.save 53 | redirect_to draft, notice: 'Your shelter update is pending approval.' 54 | else 55 | render :edit 56 | end 57 | end 58 | end 59 | 60 | def destroy 61 | end 62 | 63 | def archive 64 | if(admin?) 65 | @shelter.update_attributes(active: false) 66 | redirect_to shelters_path, notice: "Archived!" 67 | else 68 | redirect_to shelters_path, notice: "You must be an admin to archive." 69 | end 70 | end 71 | 72 | def drafts 73 | @drafts = Draft.includes(:record).where("record_type = ? OR info->>'record_type' = 'Shelter'", Shelter.name).where(accepted_by_id: nil).where(denied_by_id: nil) 74 | end 75 | 76 | private 77 | 78 | # This is the definition of a beautiful hack. 1 part gross, 2 parts simplicity. Does something neat not clever. 79 | def set_headers 80 | if(admin?) 81 | @columns = Shelter::ColumnNames + Shelter::PrivateFields 82 | @headers = Shelter::HeaderNames + Shelter::PrivateFields.map(&:titleize) 83 | else 84 | @columns = Shelter::ColumnNames 85 | @headers = Shelter::HeaderNames 86 | end 87 | end 88 | 89 | def set_shelter 90 | @shelter = Shelter.find(params[:id]) 91 | end 92 | 93 | # TODO: Test private fields are only updatable by admin 94 | def shelter_update_params 95 | if(admin?) 96 | params.require(:shelter).permit(Shelter::UpdateFields + Shelter::PrivateFields).keep_if { |_,v| v.present? } 97 | else 98 | params.require(:shelter).permit(Shelter::UpdateFields).keep_if { |_,v| v.present? } 99 | end 100 | end 101 | end 102 | -------------------------------------------------------------------------------- /app/controllers/splash_controller.rb: -------------------------------------------------------------------------------- 1 | class SplashController < ApplicationController 2 | def index 3 | # They might not have created a home key yet 4 | @page = Page.home.first_or_initialize 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | before_action :authenticate_admin! 3 | 4 | def index 5 | @users = User.all 6 | end 7 | 8 | def show 9 | @user = User.find(params[:id]) 10 | end 11 | 12 | def update 13 | @user = User.find(params[:id]) 14 | @user.update(admin: params[:admin]) 15 | 16 | redirect_to @user, notice: "User is now #{@user.admin? ? "" : "not"} an admin." 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/connect/haves_helper.rb: -------------------------------------------------------------------------------- 1 | module Connect::HavesHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/connect/needs_helper.rb: -------------------------------------------------------------------------------- 1 | module Connect::NeedsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/mucked_homes_helper.rb: -------------------------------------------------------------------------------- 1 | module MuckedHomesHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/pages_helper.rb: -------------------------------------------------------------------------------- 1 | module PagesHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/splash_helper.rb: -------------------------------------------------------------------------------- 1 | module SplashHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/volunteers_helper.rb: -------------------------------------------------------------------------------- 1 | module VolunteersHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/importers/api_importer.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'httparty' 3 | 4 | class APIImporter 5 | include HTTParty 6 | base_uri "https://api.harveyneeds.org/api/v1" 7 | format :json 8 | 9 | def self.needs 10 | get('/needs')["needs"] 11 | end 12 | 13 | def self.shelters 14 | get('/shelters')["shelters"] 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | end 3 | -------------------------------------------------------------------------------- /app/jobs/fetch_amazon_product_job.rb: -------------------------------------------------------------------------------- 1 | require 'vacuum' 2 | 3 | class FetchAmazonProductJob < ApplicationJob 4 | queue_as :default 5 | 6 | # The amazon product advertising API rate limits us pretty hard 7 | # So we need the connection_pool and redis to count our req/s 8 | # And the trafic control will re-schedule jobs 9 | throttle threshold: 10, period: 20.seconds unless Rails.env.test? 10 | 11 | def perform need 12 | 13 | request = Vacuum.new 14 | request.configure( 15 | aws_access_key_id: ENV.fetch("AWS_ACCESS_KEY_ID", "AKIAJ5PESCDQX7KIMQ5Q"), 16 | aws_secret_access_key: ENV.fetch("AWS_SECRET_ACCESS_KEY", ""), 17 | associate_tag: ENV.fetch("AWS_ASSOCIATE_TAG", "oneclickrelie-20") 18 | ) 19 | 20 | Rails.logger.debug "Finding for #{need}" 21 | 22 | response = request.item_search( 23 | query: { 24 | 'Keywords' => need, 25 | 'Availability' => 'Available', 26 | 'MerchantId' => 'Amazon', 27 | 'SearchIndex' => 'All', 28 | 'MaximumPrice' => 3000 29 | } 30 | ) 31 | 32 | error_code = response.dig("ItemSearchResponse", 33 | "Items", 34 | "Request", 35 | "Errors", 36 | "Error", 37 | "Code") 38 | 39 | if error_code == "AWS.ECommerceService.NoExactMatches" 40 | IgnoredAmazonProductNeed.create need: need 41 | return 42 | end 43 | 44 | item = response.dig('ItemSearchResponse', 'Items', 'Item') 45 | item = item.first if item.is_a? Array 46 | 47 | amazon_product = AmazonProduct 48 | .where("need ILIKE ?", "%#{need}%") 49 | .first_or_initialize 50 | amazon_product.need = need 51 | amazon_product.amazon_title = item["ItemAttributes"]["Title"] 52 | amazon_product.asin = item["ASIN"] 53 | amazon_product.detail_url = item["DetailPageURL"] 54 | 55 | amazon_product.save! 56 | end 57 | 58 | end 59 | -------------------------------------------------------------------------------- /app/jobs/import_needs_job.rb: -------------------------------------------------------------------------------- 1 | class ImportNeedsJob < ApplicationJob 2 | queue_as :default 3 | 4 | def perform(*args) 5 | logger.info "Starting ImportNeedsJob #{Time.now}" 6 | needs = APIImporter.needs 7 | needs.each do |need| 8 | # needs and cleanPhone are derived fields 9 | # updatedAt is set on save to the database 10 | Need.create! need.except("needs", "cleanPhone", "updatedAt") 11 | end 12 | logger.info "ImportNeedsJob Complete - {#{needs.count}}" 13 | 14 | # schedule an update, but it's throttled to 1 every 10 minutes 15 | ScheduleAmazonFetchJob.perform_later 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /app/jobs/import_shelters_job.rb: -------------------------------------------------------------------------------- 1 | class ImportSheltersJob < ApplicationJob 2 | queue_as :default 3 | 4 | def perform(*args) 5 | logger.info "Starting ImportSheltersJob #{Time.now}" 6 | shelters = APIImporter.shelters 7 | shelters.each do |shelter| 8 | # needs and cleanPhone are derived fields 9 | # updatedAt is set on save to the database 10 | Shelter.create! shelter.except("needs", "cleanPhone", "updatedAt") 11 | end 12 | logger.info "ImportSheltersJob Complete - {#{shelters.count}}" 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/jobs/need_update_notifier_job.rb: -------------------------------------------------------------------------------- 1 | class NeedUpdateNotifierJob < ApplicationJob 2 | queue_as :default 3 | 4 | def perform need 5 | NeedChannel.broadcast_to "needs", need: render(need) 6 | end 7 | 8 | def render need 9 | ApplicationController.render partial: 'api/v1/needs/need', 10 | locals: { 11 | need: need 12 | } 13 | end 14 | 15 | end 16 | -------------------------------------------------------------------------------- /app/jobs/schedule_amazon_fetch_job.rb: -------------------------------------------------------------------------------- 1 | class ScheduleAmazonFetchJob < ApplicationJob 2 | queue_as :default 3 | 4 | # We can get scheduled constantly, but only run once every 10 minutes 5 | # Drop otherwise 6 | throttle threshold: 1, period: 10.minutes, drop: true unless Rails.env.test? 7 | 8 | def perform(*args) 9 | Rails.logger.debug "Starting ScheduleAmazonFetchJob" 10 | 11 | Need 12 | .all 13 | .map(&:clean_needs) 14 | .flatten 15 | .uniq 16 | .reject {|need| AmazonProduct.where("need ILIKE ?", "%#{need}%").exists? } 17 | .reject {|need| IgnoredAmazonProductNeed.where("need ILIKE ?", "%#{need}%").exists? } 18 | .tap {|needs| Rails.logger.debug "ScheduleAmazonFetchJob #{needs.count}"} 19 | .each { |need| FetchAmazonProductJob.perform_later(need) } 20 | 21 | Rails.logger.debug "ScheduleAmazonFetchJob Complete" 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /app/jobs/shelter_update_notifier_job.rb: -------------------------------------------------------------------------------- 1 | class ShelterUpdateNotifierJob < ApplicationJob 2 | queue_as :default 3 | 4 | def perform shelter 5 | ShelterChannel.broadcast_to "shelters", shelter: render(shelter) 6 | end 7 | 8 | def render shelter 9 | ApplicationController.render partial: 'api/v1/shelters/shelter', 10 | locals: { 11 | shelter: shelter 12 | } 13 | end 14 | 15 | end 16 | -------------------------------------------------------------------------------- /app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: 'from@example.com' 3 | layout 'mailer' 4 | end 5 | -------------------------------------------------------------------------------- /app/models/amazon_product.rb: -------------------------------------------------------------------------------- 1 | class AmazonProduct < ApplicationRecord 2 | 3 | ColumnNames = ["need", "asin", "amazon_title", "detail_url", "priority", "disabled"] 4 | 5 | HeaderNames = ColumnNames.map(&:titleize) 6 | 7 | UpdateFields = ["need", "asin", "amazon_title", "detail_url", "priority", "disabled"] 8 | 9 | 10 | validates :need, presence: true 11 | validates :asin, presence: true 12 | validates :detail_url, presence: true 13 | 14 | scope :active, -> { where(disabled: false).proper_categories.proper_pricing} 15 | scope :priority, -> { where(priority: true)} 16 | scope :proper_categories, -> {where("category_general != ? and category_specific !=?", "", "")} 17 | scope :proper_pricing, -> { where("price_in_cents > 0")} 18 | end 19 | -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /app/models/charitable_organization.rb: -------------------------------------------------------------------------------- 1 | class CharitableOrganization < ApplicationRecord 2 | ColumnNames = %w(name services food_bank donation_website phone_number email physical_address city state zip) 3 | 4 | HeaderNames = ColumnNames.map(&:titleize) 5 | 6 | UpdateFields = %w(name services food_bank donation_website phone_number email physical_address city state zip) 7 | 8 | default_scope { where(active: true) } 9 | 10 | has_many :drafts, as: :record 11 | 12 | end 13 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sketch-city/harvey-api/00b8d9ce005a69389b665cb66c9999f39fe046d8/app/models/concerns/.keep -------------------------------------------------------------------------------- /app/models/connect.rb: -------------------------------------------------------------------------------- 1 | module Connect 2 | def self.table_name_prefix 3 | 'connect_' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/models/connect/marker.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Connect 4 | class Marker < ApplicationRecord 5 | MARKER_TYPES = %w[have need].freeze 6 | 7 | validates :categories, :device_uuid, :name, :phone, presence: true 8 | validates :marker_type, inclusion: { in: MARKER_TYPES, allow_blank: false } 9 | validates :latitude, :longitude, numericality: { other_than: 0 } 10 | validates :email, format: { with: /\A.+@.+\z/, allow_nil: true } 11 | 12 | reverse_geocoded_by :latitude, :longitude 13 | after_validation :reverse_geocode, if: :coordinates_changed? 14 | 15 | scope :by_category, ->(category) { where('categories ? :category', category: category) } 16 | scope :by_device_uuid, ->(device_uuid) { where(device_uuid: device_uuid) } 17 | scope :by_type, ->(type) { where(marker_type: type) } 18 | scope :flagged, ->() { where("data ? 'inappropriate_flag'") } 19 | scope :not_flagged, ->() { where.not("data ? 'inappropriate_flag'") } 20 | scope :resolved, -> { where(resolved: true) } 21 | scope :unresolved, -> { where(resolved: false) } 22 | 23 | def coordinates_changed? 24 | return false if latitude.zero? || longitude.zero? 25 | latitude_changed? || longitude_changed? 26 | end 27 | 28 | def flagged_inappropriate? 29 | data.key? 'inappropriate_flag' 30 | end 31 | 32 | def flag_as_inappropriate!(device_uuid:, reason:) 33 | return if flagged_inappropriate? 34 | data['inappropriate_flag'] = { 35 | flagged_by: device_uuid, 36 | flagged_for: reason, 37 | flagged_at: Time.zone.now 38 | } 39 | save 40 | end 41 | 42 | def clear_inappropriate_flag! 43 | data.delete('inappropriate_flag') 44 | save! 45 | end 46 | 47 | def flagged_by 48 | data.dig 'inappropriate_flag', 'flagged_by' 49 | end 50 | 51 | def flagged_for 52 | data.dig 'inappropriate_flag', 'flagged_for' 53 | end 54 | 55 | def flagged_at 56 | data.dig 'inappropriate_flag', 'flagged_at' 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /app/models/draft.rb: -------------------------------------------------------------------------------- 1 | class Draft < ApplicationRecord 2 | belongs_to :record, polymorphic: true, optional: true 3 | belongs_to :accepted_by, class_name: 'User', optional: true 4 | belongs_to :denied_by, class_name: 'User', optional: true 5 | end 6 | -------------------------------------------------------------------------------- /app/models/ignored_amazon_product_need.rb: -------------------------------------------------------------------------------- 1 | class IgnoredAmazonProductNeed < ApplicationRecord 2 | end 3 | -------------------------------------------------------------------------------- /app/models/location/hhrd/pois.rb: -------------------------------------------------------------------------------- 1 | class Location 2 | module HHRD 3 | class Pois < Location 4 | 5 | # Import, Models, HTML Controller, API Controller 6 | config( 7 | legacy_table_name: "point-of-interest", 8 | organization: "hurricane-harvey-rescue-dispatchers" 9 | ) 10 | 11 | filter(:rally_point, type: :truthy) 12 | filter(:launch_point, type: :truthy) 13 | filter(:diesel_fuel, type: :truthy) 14 | filter(:unleadded_fuel, type: :truthy) 15 | filter(:food, type: :truthy) 16 | filter(:hours) 17 | filter(:notes) 18 | 19 | legacy_field(:rally_point, type: :boolean) 20 | legacy_field(:launch_point, type: :boolean) 21 | legacy_field(:diesel_fuel, type: :boolean) 22 | legacy_field(:unleaded_fuel, type: :boolean) 23 | legacy_field(:food, type: :boolean) 24 | legacy_field(:hours) 25 | legacy_field(:notes) 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /app/models/location/hhrd/rescuees.rb: -------------------------------------------------------------------------------- 1 | class Location 2 | module HHRD 3 | class Rescuees < Location 4 | 5 | # Import, Models, HTML Controller, API Controller 6 | config( 7 | legacy_table_name: "rescuees", 8 | organization: "hurricane-harvey-rescue-dispatchers" 9 | ) 10 | 11 | filter(:status) 12 | filter(:tier) 13 | filter(:high_water_vehicle_accessable, type: :truthy) 14 | filter(:number_of_people) 15 | filter(:notes) 16 | 17 | legacy_field(:apartment_number) 18 | legacy_field(:status, type: :enum, options: ["Awaiting Rescue", "Boat in Route", "Rescued"]) 19 | legacy_field(:tier, type: :enum, options: ["Tier 1", "Tier 2", "None"]) 20 | legacy_field(:high_water_vehicle_accessible, type: :boolean) 21 | legacy_field(:number_of_adults) 22 | legacy_field(:number_of_elderly) 23 | legacy_field(:number_of_children) 24 | legacy_field(:number_of_pets) 25 | legacy_field(:notes) 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /app/models/location/hhrd/rescuers.rb: -------------------------------------------------------------------------------- 1 | class Location 2 | module HHRD 3 | class Rescuers < Location 4 | 5 | # Import, Models, HTML Controller, API Controller 6 | config( 7 | legacy_table_name: "rescuers", 8 | organization: "hurricane-harvey-rescue-dispatchers" 9 | ) 10 | 11 | filter(:status) 12 | filter(:background_check, type: :truthy) 13 | filter(:medic, type: :truthy) 14 | filter(:mechanic, type: :truthy) 15 | filter(:mechanic, type: :truthy) 16 | filter(:has_parts, type: :truthy) 17 | filter(:high_water_vehicle, type: :truthy) 18 | 19 | legacy_field(:status, type: :enum, options: ['in route', 'returning', 'available', 'partially occupied']) 20 | legacy_field(:vehicle_type, type: :enum, options: ['high water vehicle', 'boat']) 21 | legacy_field(:capacity) 22 | legacy_field(:background_check, type: :boolean) 23 | legacy_field(:medic, type: :boolean) 24 | legacy_field(:mechanic, type: :boolean) 25 | legacy_field(:has_parts, type: :boolean) 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /app/models/location/whitelist.rb: -------------------------------------------------------------------------------- 1 | class Location 2 | module Whitelist 3 | Locations = [HHRD::Rescuers, HHRD::Rescuees, HHRD::Pois] 4 | 5 | LocationsMap = Locations.each_with_object({}.with_indifferent_access) do |location, obj| 6 | organization = location.organization 7 | legacy_table_name = location.legacy_table_name 8 | obj[organization] ||= {}.with_indifferent_access 9 | obj[organization][legacy_table_name] ||= location 10 | end 11 | 12 | def self.find(organization, legacy_table_name) 13 | LocationsMap[organization] && LocationsMap[organization][legacy_table_name] 14 | end 15 | 16 | def self.organization_tables(organization) 17 | return nil if LocationsMap[organization].nil? 18 | 19 | keys = LocationsMap[organization].keys.sort 20 | keys.map { |key| LocationsMap[organization][key] } 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /app/models/mucked_home.rb: -------------------------------------------------------------------------------- 1 | class MuckedHome < ApplicationRecord 2 | geocoded_by :full_address 3 | end 4 | -------------------------------------------------------------------------------- /app/models/need.rb: -------------------------------------------------------------------------------- 1 | class Need < ApplicationRecord 2 | ColumnNames = ["id", "location_name", "location_address", "contact_for_this_location_name", "contact_for_this_location_phone_number", "are_supplies_needed", "tell_us_about_the_supply_needs", "are_volunteers_needed", "tell_us_about_the_volunteer_needs", "anything_else_you_would_like_to_tell_us", "source", "created_at", "updated_at", "updated_by", "latitude", "longitude"] 3 | 4 | HeaderNames = ColumnNames.map(&:titleize) 5 | 6 | UpdateFields = ["anything_else_you_would_like_to_tell_us", "are_supplies_needed", "are_volunteers_needed", "contact_for_this_location_name", "contact_for_this_location_phone_number", "created_at", "location_address", "location_name", "source", "tell_us_about_the_supply_needs", "tell_us_about_the_volunteer_needs", "updated_at", "updated_by"] 7 | 8 | has_many :drafts, as: :record 9 | 10 | geocoded_by :location_address 11 | default_scope { where(active: !false) } 12 | 13 | def clean_needs 14 | return [] if tell_us_about_the_supply_needs.blank? 15 | tell_us_about_the_supply_needs 16 | .gsub("\n","") 17 | .gsub("*", ",") 18 | .split(",") 19 | .reject{|n| n =~ /^open/i } 20 | .map(&:strip) 21 | .select(&:present?) 22 | end 23 | 24 | after_commit do 25 | NeedUpdateNotifierJob.perform_later self 26 | end 27 | 28 | before_save :calculate_values 29 | 30 | def calculate_values 31 | self.calculated_needs = (tell_us_about_the_volunteer_needs ||"").split(",") + (tell_us_about_the_supply_needs || "").split(",") 32 | self.calculated_updated_at_rfc3339 = (updated_at || Time.now).in_time_zone("Central Time (US & Canada)").rfc3339 33 | stripped_phone = (contact_for_this_location_phone_number||"").gsub(/\D/,"") 34 | self.calculated_phone = stripped_phone.match?(/^\d{10}$/) ? stripped_phone : "badphone" 35 | end 36 | 37 | def has_sufficient_data_for_map? 38 | latitude.present? and longitude.present? 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /app/models/page.rb: -------------------------------------------------------------------------------- 1 | class Page < ApplicationRecord 2 | validates :key, presence: true, uniqueness: true 3 | validates :content, presence: true 4 | 5 | scope :home, -> { where(key: "home")} 6 | scope :shelters, -> { where(key: "shelters")} 7 | end 8 | -------------------------------------------------------------------------------- /app/models/shelter.rb: -------------------------------------------------------------------------------- 1 | class Shelter < ApplicationRecord 2 | ColumnNames = ["id", "accepting", "address", "address_name", "city", "county", 3 | "state", "notes", "pets", "phone", "shelter", "source", 4 | "supply_needs", "updated_by", "volunteer_needs", 5 | "distribution_center", "food_pantry", "updated_at", 6 | "latitude", "longitude"] 7 | 8 | HeaderNames = ColumnNames.map(&:titleize) 9 | 10 | UpdateFields = ["accepting", "address", "address_name", "city", "county", 11 | "state", "notes", "pets", "phone", "shelter", "source", 12 | "supply_needs", "updated_by", "volunteer_needs", 13 | "distribution_center", "food_pantry", "latitude", "longitude"] 14 | 15 | PrivateFields = ["private_notes"] 16 | 17 | has_many :drafts, as: :record 18 | default_scope { where(active: !false) } 19 | 20 | geocoded_by :address 21 | 22 | after_commit do 23 | ShelterUpdateNotifierJob.perform_later self 24 | end 25 | 26 | before_save :calculate_values 27 | 28 | def calculate_values 29 | self.calculated_needs = (volunteer_needs || "").split(",") + (supply_needs || "").split(",") 30 | self.calculated_updated_at_rfc3339 = (updated_at || Time.now).in_time_zone("Central Time (US & Canada)").rfc3339 31 | stripped_phone = (phone||"").gsub(/\D/,"") 32 | self.calculated_phone = stripped_phone.match?(/^\d{10}$/) ? stripped_phone : "badphone" 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ApplicationRecord 2 | # Include default devise modules. Others available are: 3 | # :recoverable, :confirmable, :lockable, :timeoutable and :omniauthable 4 | devise :database_authenticatable, :registerable, 5 | :rememberable, :trackable, :validatable 6 | end 7 | -------------------------------------------------------------------------------- /app/models/volunteer.rb: -------------------------------------------------------------------------------- 1 | class Volunteer < ApplicationRecord 2 | geocoded_by :full_address 3 | end 4 | -------------------------------------------------------------------------------- /app/views/amazon_products/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_with(model: amazon_product, local: true) do |f| %> 2 | <% if amazon_product.errors.any? %> 3 |
4 | These are map markers from the Disaster Connect app 5 | that users have flagged as inappropriate. Markers that have been flagged will be hidden from 6 | public view in the apps. 7 |
8 |9 | As an admin, you have the ability to clear the flag, which will enable the public to view the 10 | marker again. Or, you can confirm that the marker is inappropriate and it will remain hidden 11 | from public view and this screen as well. 12 |
13 | 14 |18 | <% fields.map(&:titleize).each do |header| %> 19 | | <%= header %> | 20 | <% end %> 21 |
---|---|
<%= link_to 'Show', connect_flagged_marker_path(row) %> | 28 | <% fields.each do |field| %> 29 |<%= truncate(row.public_send(field).to_s) %> | 30 | <% end %> 31 |
Flagged At: <%= @flagged_marker.flagged_at %>
16 |Flagged For: <%= @flagged_marker.flagged_for %>
17 |Flagged By: <%= @flagged_marker.flagged_by %>
18 | 19 |<%= JSON.pretty_generate @flagged_marker.as_json %>
21 | Field | 12 |Current Value | 13 |New Value | 14 |<%= @headers[index] %> | 22 |<%= @record.send(column) %> | 23 |<%= @draft.info[column.to_s] || @record.send(column) %> | 24 | <% end %> 25 | <% end %> 26 | 27 |
---|
Field | 38 |Value | 39 |<%= @headers[index] %> | 47 |<%= @draft.info[column.to_s] %> | 48 | <% end %> 49 | <% end %> 50 | 51 |
---|
<%= notice %>
56 |<%= alert %>
57 | 58 | <%= yield %> 59 |Field | 12 |Current Value | 13 |New Value | 14 |<%= @headers[index] %> | 22 |<%= @record.send(column) %> | 23 |<%= @draft.info[column.to_s] || @record.send(column) %> | 24 | <% end %> 25 | <% end %> 26 | 27 |
---|
Field | 38 |Value | 39 |<%= @headers[index] %> | 47 |<%= @draft.info[column.to_s] %> | 48 | <% end %> 49 | <% end %> 50 | 51 |
---|
NOTE: You must fill out the name, address, city, state and zip or the system will be unable to add the lat/lon to record and it will not appear on the map!2 | <%= form_for(location, url: path, method: method, local: true) do |f| %> 3 | <% if location.errors.any? %> 4 |
7 | <% @headers.each do |header| %> 8 | | <%= header %> | 9 | <% end %> 10 |
---|---|
<%= link_to 'Show', location_draft_path(organization: @organization, legacy_table_name: @legacy_table_name, id: draft.id) %> | 17 | <% @columns.each do |column| %> 18 |<%= truncate((draft.info[column.to_s] || @locations[draft.record_id] && @locations[draft.record_id].send(column)).to_s) %> | 19 | <% end %> 20 |
34 | | Geocoded? | 35 | <% @headers.each do |header| %> 36 |<%= header %> | 37 | <% end %> 38 |
---|---|---|
<%= link_to 'Show', location_path(organization: @organization, legacy_table_name: @legacy_table_name, id: location.id) %> / <%= link_to 'Update', edit_location_path(organization: @organization, legacy_table_name: @legacy_table_name, id: location.id) %> | 45 |<%= location.latitude.present? && location.longitude.present? %> | 46 | <% @columns.each do |column| %> 47 |<%= truncate(location.send(column).to_s) %> | 48 | <% end %> 49 |
<%= header %> | 6 | <% end %> 7 |8 | | |
---|---|---|
15 | <% if user_signed_in? && current_user.admin? && row.accepted_by_id.nil? && row.denied_by_id.nil? %> 16 | <%= link_to 'Accept', [:accept, row], {class: "button", method: :post} %> 17 | <%= link_to 'Deny', row, {class: "button button-outline", method: :delete} %> 18 | <% end %> 19 | | 20 | 21 |<%= link_to 'Show', row %> | 22 | 23 | 24 | <% columns.each do |column| %> 25 |<%= truncate((row.info[column.to_s] || row.record && row.record.send(column)).to_s) %> | 26 | <% end %> 27 |
3 | <%= headers[index] %>: 4 | <%= record.public_send(column) %> 5 |
6 | <% end %> 7 | -------------------------------------------------------------------------------- /app/views/shared/_table.html.erb: -------------------------------------------------------------------------------- 1 |5 | <% headers.each do |header| %> 6 | | <%= header %> | 7 | <% end %> 8 |
---|---|
<%= link_to 'Show', row %> / <%= link_to 'Update', [:edit, row] %> | 15 | <% columns.each do |column| %> 16 |<%= truncate(row.public_send(column).to_s) %> | 17 | <% end %> 18 |
Admin? | 8 |9 | | |
---|---|---|
<%= user.email %> | 16 |<%= user.admin? ? "Yes" : "No" %> | 17 |<%= link_to "View", user %> | 18 |
Admin: <%= @user.admin? ? "Yes" : "No" %>
3 | 4 | <% if @user.admin? %> 5 | <%= link_to "Revoke Admin", user_path(id: @user.id, admin: 0), class: "button", method: :put %> 6 | <% else %> 7 | <%= link_to "Make Admin", user_path(id: @user.id, admin: 1), class: "button", method: :put %> 8 | <% end %> 9 | -------------------------------------------------------------------------------- /app/views/users/update.html.erb: -------------------------------------------------------------------------------- 1 |Find me in app/views/users/update.html.erb
3 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path('../spring', __FILE__) 4 | rescue LoadError => e 5 | raise unless e.message.include?('spring') 6 | end 7 | APP_PATH = File.expand_path('../config/application', __dir__) 8 | require_relative '../config/boot' 9 | require 'rails/commands' 10 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path('../spring', __FILE__) 4 | rescue LoadError => e 5 | raise unless e.message.include?('spring') 6 | end 7 | require_relative '../config/boot' 8 | require 'rake' 9 | Rake.application.run 10 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a starting point to setup your application. 15 | # Add necessary setup steps to this file. 16 | 17 | puts '== Installing dependencies ==' 18 | system! 'gem install bundler --conservative' 19 | system('bundle check') || system!('bundle install') 20 | 21 | # Install JavaScript dependencies if using Yarn 22 | # system('bin/yarn') 23 | 24 | 25 | # puts "\n== Copying sample files ==" 26 | # unless File.exist?('config/database.yml') 27 | # cp 'config/database.yml.sample', 'config/database.yml' 28 | # end 29 | 30 | puts "\n== Preparing database ==" 31 | system! 'bin/rails db:setup' 32 | 33 | puts "\n== Removing old logs and tempfiles ==" 34 | system! 'bin/rails log:clear tmp:clear' 35 | 36 | puts "\n== Restarting application server ==" 37 | system! 'bin/rails restart' 38 | end 39 | -------------------------------------------------------------------------------- /bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This file loads spring without using Bundler, in order to be fast. 4 | # It gets overwritten when you run the `spring binstub` command. 5 | 6 | unless defined?(Spring) 7 | require 'rubygems' 8 | require 'bundler' 9 | 10 | lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read) 11 | spring = lockfile.specs.detect { |spec| spec.name == "spring" } 12 | if spring 13 | Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path 14 | gem 'spring', spring.version 15 | require 'spring/binstub' 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a way to update your development environment automatically. 15 | # Add necessary update steps to this file. 16 | 17 | puts '== Installing dependencies ==' 18 | system! 'gem install bundler --conservative' 19 | system('bundle check') || system!('bundle install') 20 | 21 | puts "\n== Updating database ==" 22 | system! 'bin/rails db:migrate' 23 | 24 | puts "\n== Removing old logs and tempfiles ==" 25 | system! 'bin/rails log:clear tmp:clear' 26 | 27 | puts "\n== Restarting application server ==" 28 | system! 'bin/rails restart' 29 | end 30 | -------------------------------------------------------------------------------- /bin/yarn: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | VENDOR_PATH = File.expand_path('..', __dir__) 3 | Dir.chdir(VENDOR_PATH) do 4 | begin 5 | exec "yarnpkg #{ARGV.join(" ")}" 6 | rescue Errno::ENOENT 7 | $stderr.puts "Yarn executable was not detected in the system." 8 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" 9 | exit 1 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative 'config/environment' 4 | 5 | run Rails.application 6 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative 'boot' 2 | 3 | require 'rails/all' 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | 9 | module HarveyApi 10 | class Application < Rails::Application 11 | # Initialize configuration defaults for originally generated Rails version. 12 | config.load_defaults 5.1 13 | 14 | # Settings in config/environments/* take precedence over those specified here. 15 | # Application configuration should go into files in config/initializers 16 | # -- all .rb files in that directory are automatically loaded. 17 | 18 | config.middleware.insert_before 0, Rack::Cors do 19 | allow do 20 | origins '*' 21 | resource '*', :headers => :any, :methods => [:get, :post, :options] 22 | end 23 | end 24 | 25 | config.active_job.queue_adapter = :sucker_punch 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: redis 3 | url: redis://127.0.0.1:6379/1 4 | channel_prefix: harvey-api_development 5 | 6 | test: 7 | adapter: redis 8 | url: redis://127.0.0.1:6379/2 9 | channel_prefix: harvey-api_test 10 | 11 | production: 12 | adapter: redis 13 | url: <%= ENV["REDIS_URL"] %> 14 | channel_prefix: harvey-api_production 15 | -------------------------------------------------------------------------------- /config/database.yml.travis: -------------------------------------------------------------------------------- 1 | test: 2 | adapter: postgresql 3 | database: travis_ci_test 4 | username: postgres 5 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative 'application' 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports. 13 | config.consider_all_requests_local = true 14 | 15 | # Enable/disable caching. By default caching is disabled. 16 | if Rails.root.join('tmp/caching-dev.txt').exist? 17 | config.action_controller.perform_caching = true 18 | 19 | config.cache_store = :memory_store 20 | config.public_file_server.headers = { 21 | 'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}" 22 | } 23 | else 24 | config.action_controller.perform_caching = false 25 | 26 | config.cache_store = :null_store 27 | end 28 | 29 | # Don't care if the mailer can't send. 30 | config.action_mailer.raise_delivery_errors = false 31 | 32 | config.action_mailer.perform_caching = false 33 | 34 | # Print deprecation notices to the Rails logger. 35 | config.active_support.deprecation = :log 36 | 37 | # Raise an error on page load if there are pending migrations. 38 | config.active_record.migration_error = :page_load 39 | 40 | # Debug mode disables concatenation and preprocessing of assets. 41 | # This option may cause significant delays in view rendering with a large 42 | # number of complex assets. 43 | config.assets.debug = true 44 | 45 | # Suppress logger output for asset requests. 46 | config.assets.quiet = true 47 | 48 | # Raises error for missing translations 49 | # config.action_view.raise_on_missing_translations = true 50 | 51 | # Use an evented file watcher to asynchronously detect changes in source code, 52 | # routes, locales, etc. This feature depends on the listen gem. 53 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker 54 | end 55 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure public file server for tests with Cache-Control for performance. 16 | config.public_file_server.enabled = true 17 | config.public_file_server.headers = { 18 | 'Cache-Control' => "public, max-age=#{1.hour.seconds.to_i}" 19 | } 20 | 21 | # Show full error reports and disable caching. 22 | config.consider_all_requests_local = true 23 | config.action_controller.perform_caching = false 24 | 25 | # Raise exceptions instead of rendering exception templates. 26 | config.action_dispatch.show_exceptions = false 27 | 28 | # Disable request forgery protection in test environment. 29 | config.action_controller.allow_forgery_protection = false 30 | config.action_mailer.perform_caching = false 31 | 32 | # Tell Action Mailer not to deliver emails to the real world. 33 | # The :test delivery method accumulates sent emails in the 34 | # ActionMailer::Base.deliveries array. 35 | config.action_mailer.delivery_method = :test 36 | 37 | # Print deprecation notices to the stderr. 38 | config.active_support.deprecation = :stderr 39 | 40 | # Raises error for missing translations 41 | # config.action_view.raise_on_missing_translations = true 42 | end 43 | -------------------------------------------------------------------------------- /config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ApplicationController.renderer.defaults.merge!( 4 | # http_host: 'example.org', 5 | # https: false 6 | # ) 7 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | # Add Yarn node_modules folder to the asset load path. 9 | Rails.application.config.assets.paths << Rails.root.join('node_modules') 10 | 11 | # Precompile additional assets. 12 | # application.js, application.css, and all non-JS/CSS in the app/assets 13 | # folder are already added. 14 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 15 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /config/initializers/geocoder.rb: -------------------------------------------------------------------------------- 1 | Geocoder.configure( 2 | # Geocoding options 3 | # timeout: 3, # geocoding service timeout (secs) 4 | lookup: :google, # name of geocoding service (symbol) 5 | # ip_lookup: :freegeoip, # name of IP address geocoding service (symbol) 6 | # language: :en, # ISO-639 language code 7 | use_https: true, # use HTTPS for lookup requests? (if supported) 8 | # http_proxy: nil, # HTTP proxy server (user:pass@host:port) 9 | # https_proxy: nil, # HTTPS proxy server (user:pass@host:port) 10 | api_key: ENV.fetch('GOOGLE_GEOCODER_API_KEY', ""), # API key for geocoding service 11 | # cache: nil, # cache object (must respond to #[], #[]=, and #del) 12 | # cache_prefix: 'geocoder:', # prefix (string) to use for all cache keys 13 | 14 | # Exceptions that should not be rescued by default 15 | # (if you want to implement custom error handling); 16 | # supports SocketError and Timeout::Error 17 | # always_raise: [], 18 | 19 | # Calculation options 20 | # units: :mi, # :km for kilometers or :mi for miles 21 | # distances: :linear # :spherical or :linear 22 | ) 23 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /config/initializers/traffic_cop.rb: -------------------------------------------------------------------------------- 1 | require "connection_pool" 2 | 3 | # The amazon product advertising API rate limits us pretty hard 4 | # So we need the connection_pool and redis to count our req/s 5 | # And the trafic control will re-schedule jobs 6 | ActiveJob::TrafficControl.client = ConnectionPool.new(size: 5, timeout: 5) { Redis.new } 7 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # 'true': 'foo' 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at http://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | -------------------------------------------------------------------------------- /config/locales/simple_form.en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | simple_form: 3 | "yes": 'Yes' 4 | "no": 'No' 5 | required: 6 | text: 'required' 7 | mark: '*' 8 | # You can uncomment the line below if you need to overwrite the whole required html. 9 | # When using html, text and mark won't be used. 10 | # html: '*' 11 | error_notification: 12 | default_message: "Please review the problems below:" 13 | # Examples 14 | # labels: 15 | # defaults: 16 | # password: 'Password' 17 | # user: 18 | # new: 19 | # email: 'E-mail to sign in.' 20 | # edit: 21 | # email: 'E-mail.' 22 | # hints: 23 | # defaults: 24 | # username: 'User name to sign in.' 25 | # password: 'No special characters, please.' 26 | # include_blanks: 27 | # defaults: 28 | # age: 'Rather not say' 29 | # prompts: 30 | # defaults: 31 | # age: 'Select your age' 32 | -------------------------------------------------------------------------------- /config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers: a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum; this matches the default thread size of Active Record. 6 | # 7 | threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } 8 | threads threads_count, threads_count 9 | 10 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 11 | # 12 | port ENV.fetch("PORT") { 3000 } 13 | 14 | # Specifies the `environment` that Puma will run in. 15 | # 16 | environment ENV.fetch("RAILS_ENV") { "development" } 17 | 18 | # Specifies the number of `workers` to boot in clustered mode. 19 | # Workers are forked webserver processes. If using threads and workers together 20 | # the concurrency of the application would be max `threads` * `workers`. 21 | # Workers do not work on JRuby or Windows (both of which do not support 22 | # processes). 23 | # 24 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 25 | 26 | # Use the `preload_app!` method when specifying a `workers` number. 27 | # This directive tells Puma to first boot the application and load code 28 | # before forking the application. This takes advantage of Copy On Write 29 | # process behavior so workers use less memory. If you use this option 30 | # you need to make sure to reconnect any threads in the `on_worker_boot` 31 | # block. 32 | # 33 | # preload_app! 34 | 35 | # If you are preloading your application and using Active Record, it's 36 | # recommended that you close any connections to the database before workers 37 | # are forked to prevent connection leakage. 38 | # 39 | # before_fork do 40 | # ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord) 41 | # end 42 | 43 | # The code in the `on_worker_boot` will be called if you are using 44 | # clustered mode by specifying a number of `workers`. After each worker 45 | # process is booted, this block will be run. If you are using the `preload_app!` 46 | # option, you will want to use this block to reconnect to any threads 47 | # or connections that may have been created at application boot, as Ruby 48 | # cannot share connections between processes. 49 | # 50 | # on_worker_boot do 51 | # ActiveRecord::Base.establish_connection if defined?(ActiveRecord) 52 | # end 53 | # 54 | 55 | # Allow puma to be restarted by `rails restart` command. 56 | plugin :tmp_restart 57 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | 3 | devise_for :users 4 | 5 | resources :users, only: [:index, :show, :update] 6 | resources :charitable_organizations do 7 | get :drafts, on: :collection 8 | post :archive, on: :member 9 | end 10 | resources :shelters do 11 | get :drafts, on: :collection 12 | post :archive, on: :member 13 | end 14 | resources :needs do 15 | get :drafts, on: :collection 16 | post :archive, on: :member 17 | end 18 | resources :drafts, only: [:show, :destroy] do 19 | post :accept, on: :member 20 | end 21 | resources :amazon_products, except: [:new, :create, :destroy] 22 | namespace :connect do 23 | resources :flagged_markers, only: [:index, :show, :update, :destroy] 24 | end 25 | 26 | root to: "splash#index" 27 | 28 | namespace :api, defaults: { format: :json } do 29 | namespace :v1 do 30 | 31 | get "/needs" => 'needs#index' 32 | get "/shelters" => 'shelters#index' 33 | get "/products" => 'amazon_products#index' 34 | get "/charitable_organizations" => 'charitable_organizations#index' 35 | 36 | namespace :connect do 37 | resources :markers, only: [:create, :index, :update] do 38 | resource :flag, only: :create 39 | end 40 | resources :categories, only: [:index] 41 | end 42 | end 43 | end 44 | 45 | resources :pages, only: [:index, :edit, :update, :destroy] 46 | 47 | # API JSON v2 48 | namespace :api, defaults: { format: :json } do 49 | namespace :v2 do 50 | get "/routes" => 'locations#routes' 51 | get "/:organization/:legacy_table_name" => 'locations#index', as: "api_locations" 52 | get "/:organization/:legacy_table_name/help" => 'locations#help', as: "api_locations_help" 53 | end 54 | end 55 | # HTML Pages v2 Locations 56 | get ":organization/:legacy_table_name", to: "locations#index", as: "locations" 57 | post ":organization/:legacy_table_name", to: "locations#create" 58 | get ":organization/:legacy_table_name/new", to: "locations#new", as: "new_location" 59 | get ":organization/:legacy_table_name/drafts", to: "locations#drafts", as: "drafts_locations" 60 | get ":organization/:legacy_table_name/:id/edit", to: "locations#edit", as: "edit_location" 61 | post ":organization/:legacy_table_name/:id/archive", to: "locations#archive", as: "archive_location" 62 | get ":organization/:legacy_table_name/:id", to: "locations#show", as: "location" 63 | put ":organization/:legacy_table_name/:id", to: "locations#update" 64 | # HTML Pages v2 Location Drafts 65 | post ":organization/:legacy_table_name/drafts/:id/accept", to: "location_drafts#accept", as: "accept_location_draft" 66 | get ":organization/:legacy_table_name/drafts/:id", to: "location_drafts#show", as: "location_draft" 67 | delete ":organization/:legacy_table_name/drafts/:id", to: "location_drafts#destroy" 68 | # HTML Pages v2 Organizations 69 | get ":organization", to: "organizations#show", as: "organization" 70 | 71 | 72 | end 73 | -------------------------------------------------------------------------------- /config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rails secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | # Shared secrets are available across all environments. 14 | 15 | # shared: 16 | # api_key: a1B2c3D4e5F6 17 | 18 | # Environmental secrets are only available for that specific environment. 19 | 20 | development: 21 | secret_key_base: d22cd95910c4425ab8adfd2aa968b845775c6ffff23f9cdb337bc6f210199ca97736ed261d06bf69242f6483a8e6c474ab88f02dabb9865f9911ff215da31695 22 | 23 | test: 24 | secret_key_base: 44caab1bd8c8d8cf74981bfc824b9c0a1786d7bc3a2d6b09f493f69b3fdd0c76b19d1e587545be50f8f4ae3fd66506b8b113a00a98ae7f8e7b00bf4b21690aeb 25 | 26 | # Do not keep production secrets in the unencrypted secrets file. 27 | # Instead, either read values from the environment. 28 | # Or, use `bin/rails secrets:setup` to configure encrypted secrets 29 | # and move the `production:` environment over there. 30 | 31 | production: 32 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 33 | -------------------------------------------------------------------------------- /config/spring.rb: -------------------------------------------------------------------------------- 1 | %w( 2 | .ruby-version 3 | .rbenv-vars 4 | tmp/restart.txt 5 | tmp/caching-dev.txt 6 | ).each { |path| Spring.watch(path) } 7 | -------------------------------------------------------------------------------- /db/migrate/20170831193310_create_shelters.rb: -------------------------------------------------------------------------------- 1 | class CreateShelters < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :shelters do |t| 4 | 5 | t.string :county 6 | t.string :shelter 7 | t.string :address 8 | t.string :city 9 | t.string :pets 10 | t.string :phone 11 | t.boolean :accepting 12 | t.string :last_updated 13 | t.string :updated_by 14 | t.string :notes 15 | t.string :volunteer_needs 16 | t.string :longitude 17 | t.string :latitude 18 | t.string :supply_needs 19 | t.string :source 20 | t.string :address_name 21 | 22 | t.timestamps 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /db/migrate/20170831193314_create_needs.rb: -------------------------------------------------------------------------------- 1 | class CreateNeeds < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :needs do |t| 4 | 5 | t.string :updated_by 6 | t.string :timestamp 7 | t.string :location_name 8 | t.string :location_address 9 | t.string :longitude 10 | t.string :latitude 11 | t.string :contact_for_this_location_name 12 | t.string :contact_for_this_location_phone_number 13 | t.boolean :are_volunteers_needed 14 | t.string :tell_us_about_the_volunteer_needs 15 | t.boolean :are_supplies_needed 16 | t.string :tell_us_about_the_supply_needs 17 | t.string :anything_else_you_would_like_to_tell_us 18 | t.string :source 19 | t.timestamps 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /db/migrate/20170831220720_change_lat_long_to_floats.rb: -------------------------------------------------------------------------------- 1 | class ChangeLatLongToFloats < ActiveRecord::Migration[5.1] 2 | def change 3 | execute("DELETE FROM shelters") 4 | execute("DELETE FROM needs") 5 | 6 | execute("ALTER TABLE shelters ALTER COLUMN latitude TYPE float USING (latitude::float)") 7 | execute("ALTER TABLE shelters ALTER COLUMN longitude TYPE float USING (longitude::float)") 8 | execute("ALTER TABLE needs ALTER COLUMN latitude TYPE float USING (latitude::float)") 9 | execute("ALTER TABLE needs ALTER COLUMN longitude TYPE float USING (longitude::float)") 10 | 11 | 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20170901185804_add_update_draft_table.rb: -------------------------------------------------------------------------------- 1 | class AddUpdateDraftTable < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :drafts do |t| 4 | t.jsonb :info 5 | t.timestamps 6 | end 7 | 8 | add_reference(:drafts, :record, polymorphic: true) 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20170901194923_devise_create_users.rb: -------------------------------------------------------------------------------- 1 | class DeviseCreateUsers < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :users do |t| 4 | # Admin 5 | t.boolean :admin 6 | 7 | ## Database authenticatable 8 | t.string :email, null: false, default: "" 9 | t.string :encrypted_password, null: false, default: "" 10 | 11 | ## Recoverable 12 | t.string :reset_password_token 13 | t.datetime :reset_password_sent_at 14 | 15 | ## Rememberable 16 | t.datetime :remember_created_at 17 | 18 | ## Trackable 19 | t.integer :sign_in_count, default: 0, null: false 20 | t.datetime :current_sign_in_at 21 | t.datetime :last_sign_in_at 22 | t.inet :current_sign_in_ip 23 | t.inet :last_sign_in_ip 24 | 25 | ## Confirmable 26 | t.string :confirmation_token 27 | t.datetime :confirmed_at 28 | t.datetime :confirmation_sent_at 29 | t.string :unconfirmed_email # Only if using reconfirmable 30 | 31 | ## Lockable 32 | # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts 33 | # t.string :unlock_token # Only if unlock strategy is :email or :both 34 | # t.datetime :locked_at 35 | 36 | 37 | t.timestamps null: false 38 | end 39 | 40 | add_index :users, :email, unique: true 41 | add_index :users, :reset_password_token, unique: true 42 | add_index :users, :confirmation_token, unique: true 43 | # add_index :users, :unlock_token, unique: true 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /db/migrate/20170901201514_create_amazon_products.rb: -------------------------------------------------------------------------------- 1 | class CreateAmazonProducts < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :amazon_products do |t| 4 | t.string :need, unique: true, allow_null: false 5 | t.string :amazon_title, allow_null: false 6 | t.string :asin, allow_null: false 7 | t.string :detail_url, allow_null: false 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20170901224459_add_accept_deny_draft.rb: -------------------------------------------------------------------------------- 1 | class AddAcceptDenyDraft < ActiveRecord::Migration[5.1] 2 | def change 3 | add_reference :drafts, :accepted_by, {foreign_key: {to_table: :users}} 4 | add_reference :drafts, :denied_by, {foreign_key: {to_table: :users}} 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20170902123713_add_disabled_to_amazon_products.rb: -------------------------------------------------------------------------------- 1 | class AddDisabledToAmazonProducts < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :amazon_products, :priority, :boolean, default: false 4 | add_column :amazon_products, :disabled, :boolean, default: false 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20170902140452_create_ignored_amazon_product_needs.rb: -------------------------------------------------------------------------------- 1 | class CreateIgnoredAmazonProductNeeds < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :ignored_amazon_product_needs do |t| 4 | t.string :need 5 | 6 | t.timestamps 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20170902203116_add_archive_to_need.rb: -------------------------------------------------------------------------------- 1 | class AddArchiveToNeed < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :needs, :active, :boolean, default: true 4 | add_column :shelters, :active, :boolean, default: true 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20170902213139_create_mucked_homes.rb: -------------------------------------------------------------------------------- 1 | class CreateMuckedHomes < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :mucked_homes do |t| 4 | t.string :name 5 | t.text :description 6 | t.string :phone 7 | t.string :pin 8 | t.float :latitude 9 | t.float :longitude 10 | 11 | t.timestamps 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20170902222739_create_volunteers.rb: -------------------------------------------------------------------------------- 1 | class CreateVolunteers < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :volunteers do |t| 4 | t.string :name 5 | t.text :description 6 | t.string :phone 7 | t.string :pin 8 | t.float :latitude 9 | t.float :longitude 10 | 11 | t.timestamps 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20170903113333_create_connect_markers.rb: -------------------------------------------------------------------------------- 1 | class CreateConnectMarkers < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :connect_markers do |t| 4 | t.string :marker_type, null: false 5 | t.string :name, null: false, default: "" 6 | t.text :description, null: false, default: "" 7 | t.string :phone, null: false, default: "" 8 | t.string :category, null: false, default: "" 9 | t.boolean :resolved, null: false, default: false 10 | t.float :latitude, null: false, default: 0.0 11 | t.float :longitude, null: false, default: 0.0 12 | t.string :address, null: false, default: "" 13 | 14 | t.timestamps 15 | end 16 | add_index :connect_markers, [:latitude, :longitude] 17 | add_index :connect_markers, :category 18 | add_index :connect_markers, :resolved, name: "index_connect_markers_on_unresolved", where: "(resolved IS FALSE)" 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /db/migrate/20170903230413_create_charitable_organizations.rb: -------------------------------------------------------------------------------- 1 | class CreateCharitableOrganizations < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :charitable_organizations do |t| 4 | t.string :name 5 | t.string :services 6 | t.boolean :food_bank 7 | t.string :donation_website 8 | t.string :phone_number 9 | t.string :email 10 | t.string :physical_address 11 | t.string :city 12 | t.string :state 13 | t.string :zip 14 | 15 | t.timestamps 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /db/migrate/20170903231428_add_archive_to_charitable_organizations.rb: -------------------------------------------------------------------------------- 1 | class AddArchiveToCharitableOrganizations < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :charitable_organizations, :active, :boolean, default: true, null: false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20170904025322_add_email_to_connect_markers.rb: -------------------------------------------------------------------------------- 1 | class AddEmailToConnectMarkers < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :connect_markers, :email, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20170904165336_add_product_categories_to_amazon_products.rb: -------------------------------------------------------------------------------- 1 | class AddProductCategoriesToAmazonProducts < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :amazon_products, :category_specific, :string, default: "" 4 | add_column :amazon_products, :category_general, :string, default: "" 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20170905114546_add_data_to_markers.rb: -------------------------------------------------------------------------------- 1 | class AddDataToMarkers < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :connect_markers, :data, :jsonb, null: false, default: {} 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20170905201043_create_pages.rb: -------------------------------------------------------------------------------- 1 | class CreatePages < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :pages do |t| 4 | t.string :key, default: "", unique: true, null: false 5 | t.text :content, default: "", null: false 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20170906160409_add_amazon_price_to_products.rb: -------------------------------------------------------------------------------- 1 | class AddAmazonPriceToProducts < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :amazon_products, :price_in_cents, :integer, default: 0 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20170907032253_add_fields_to_shelter.rb: -------------------------------------------------------------------------------- 1 | class AddFieldsToShelter < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :shelters, :private_notes, :text 4 | add_column :shelters, :distribution_center, :text 5 | add_column :shelters, :food_pantry, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20170907070934_add_location_table.rb: -------------------------------------------------------------------------------- 1 | class AddLocationTable < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :locations do |t| 4 | # Core location information 5 | t.string :name 6 | t.string :address 7 | t.string :city 8 | t.string :state 9 | t.string :zip 10 | t.string :phone 11 | t.boolean :active, default: true, null: false 12 | # Storage for legacy information 13 | t.string :organization 14 | t.string :legacy_table_name 15 | t.jsonb :legacy_data, default: {}, null: false 16 | t.float :latitude 17 | t.float :longitude 18 | 19 | t.timestamps 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /db/migrate/20170907152426_add_device_uuid_connect_markers.rb: -------------------------------------------------------------------------------- 1 | class AddDeviceUuidConnectMarkers < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :connect_markers, :device_uuid, :string, null: false, default: '' 4 | add_index :connect_markers, :device_uuid 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20170908152859_update_category_on_connect_markers.rb: -------------------------------------------------------------------------------- 1 | class UpdateCategoryOnConnectMarkers < ActiveRecord::Migration[5.1] 2 | def change 3 | # This will lose data, but we don't need/want it anyways 4 | remove_column :connect_markers, :category, :string, null: false, default: "" 5 | add_column :connect_markers, :categories, :jsonb, null: false, default: {} 6 | add_index :connect_markers, :categories, using: :gin 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20170911052811_add_state_to_shelter.rb: -------------------------------------------------------------------------------- 1 | class AddStateToShelter < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :shelters, :state, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20170911205637_add_indexes.rb: -------------------------------------------------------------------------------- 1 | class AddIndexes < ActiveRecord::Migration[5.1] 2 | def change 3 | add_index :shelters, :active 4 | add_index :shelters, :accepting 5 | add_index :shelters, [:latitude, :longitude] 6 | add_index :needs, :active 7 | add_index :needs, [:latitude, :longitude] 8 | add_index :locations, :active 9 | add_index :locations, [:latitude, :longitude] 10 | add_index :charitable_organizations, :active 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20170911210028_add_calculated_values_for_shelters.rb: -------------------------------------------------------------------------------- 1 | class AddCalculatedValuesForShelters < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :shelters, :calculated_needs, :string, array: true 4 | add_column :shelters, :calculated_updated_at_rfc3339, :string 5 | add_column :shelters, :calculated_phone, :string 6 | 7 | add_column :needs, :calculated_needs, :string, array: true 8 | add_column :needs, :calculated_updated_at_rfc3339, :string 9 | add_column :needs, :calculated_phone, :string 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20170920210424_add_index_to_data_on_connect_markers.rb: -------------------------------------------------------------------------------- 1 | class AddIndexToDataOnConnectMarkers < ActiveRecord::Migration[5.1] 2 | def change 3 | add_index :connect_markers, :data, using: :gin 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | amazon_json = JSON.parse File.read("#{Rails.root}/db/seeds/amazon_products.json") 2 | amazon_json.each do |json| 3 | ap = AmazonProduct.where(need: json["need"]).first_or_initialize 4 | ap.attributes = json 5 | ap.save 6 | end 7 | 8 | ignored_json = JSON.parse File.read("#{Rails.root}/db/seeds/ignored_amazon_product_needs.json") 9 | ignored_json.each do |json| 10 | iapn= IgnoredAmazonProductNeed.where(need: json["need"]).first_or_initialize 11 | iapn.attributes = json 12 | iapn.save 13 | end 14 | 15 | 16 | Page.home.first_or_create content: "#Welcome" 17 | -------------------------------------------------------------------------------- /lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sketch-city/harvey-api/00b8d9ce005a69389b665cb66c9999f39fe046d8/lib/assets/.keep -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sketch-city/harvey-api/00b8d9ce005a69389b665cb66c9999f39fe046d8/lib/tasks/.keep -------------------------------------------------------------------------------- /lib/tasks/data.rake: -------------------------------------------------------------------------------- 1 | namespace :data do 2 | desc "Calculate Shelter and Needs values" 3 | task :calculate_values => :environment do 4 | 5 | Shelter.find_each do |shelter| 6 | shelter.calculate_values 7 | shelter.save 8 | end 9 | 10 | Need.find_each do |need| 11 | need.calculate_values 12 | need.save 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/tasks/import.rake: -------------------------------------------------------------------------------- 1 | namespace :api do 2 | desc "Schedule import of records for needs and shelters" 3 | task :import => :environment do 4 | if Rails.env.development? 5 | ImportSheltersJob.perform_now 6 | ImportNeedsJob.perform_now 7 | else 8 | puts "Not running api:import because it's not development mode. Mode: #{Rails.env}" 9 | end 10 | end 11 | end 12 | 13 | namespace :amazon do 14 | desc "Schedule import of Amazon Products" 15 | task :import => :environment do 16 | ScheduleAmazonFetchJob.perform_now 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/templates/erb/scaffold/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%%= simple_form_for(@<%= singular_table_name %>) do |f| %> 2 | <%%= f.error_notification %> 3 | 4 |You may have mistyped the address or the page may have moved.
63 |If you are the application owner check the logs for more information.
65 |Maybe you tried to change something you didn't have access to.
63 |If you are the application owner check the logs for more information.
65 |If you are the application owner check the logs for more information.
64 |Below are a list of our contributors
14 |