+ <% end %>
+ <%# can we have an associated image for a category or that would be too much because then you'd have to include that in the form when creating a new category? %>
+ <%# Instead of an image, we could just have some nice text in a clickable box? %>
+ <% end %>
+
+
+
+<%= form_for @review do |f| %>
+
+ <% rating_array = [] %>
+ <% (1..5).each do |rating|
+ stars = render partial: "/layouts/stars", locals: {rating: rating}
+ rating_array << [stars, rating]
+ end %>
+
+ <%= f.select :rating, rating_array, {include_blank: 'Select a rating'}, :selected => rating_array[:rating.to_s.to_i - 1] %>
+
+ <%# f.label :rating, "Rating 1-5" %>
+ <%# f.select :rating, [1,2,3,4,5] %>
+
+ <%= f.label :text, "Write a review!" %>
+ <%= f.text_area :text %>
+
+ <%= f.hidden_field :product_id, value: @product.id %>
+
+ <%= f.submit "Submit", class:'button' %>
+
+<% end %>
+
diff --git a/bin/bundle b/bin/bundle
new file mode 100755
index 0000000000..66e9889e8b
--- /dev/null
+++ b/bin/bundle
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
+load Gem.bin_path('bundler', 'bundle')
diff --git a/bin/rails b/bin/rails
new file mode 100755
index 0000000000..5badb2fde0
--- /dev/null
+++ b/bin/rails
@@ -0,0 +1,9 @@
+#!/usr/bin/env ruby
+begin
+ load File.expand_path('../spring', __FILE__)
+rescue LoadError => e
+ raise unless e.message.include?('spring')
+end
+APP_PATH = File.expand_path('../config/application', __dir__)
+require_relative '../config/boot'
+require 'rails/commands'
diff --git a/bin/rake b/bin/rake
new file mode 100755
index 0000000000..d87d5f5781
--- /dev/null
+++ b/bin/rake
@@ -0,0 +1,9 @@
+#!/usr/bin/env ruby
+begin
+ load File.expand_path('../spring', __FILE__)
+rescue LoadError => e
+ raise unless e.message.include?('spring')
+end
+require_relative '../config/boot'
+require 'rake'
+Rake.application.run
diff --git a/bin/setup b/bin/setup
new file mode 100755
index 0000000000..78c4e861dc
--- /dev/null
+++ b/bin/setup
@@ -0,0 +1,38 @@
+#!/usr/bin/env ruby
+require 'pathname'
+require 'fileutils'
+include FileUtils
+
+# path to your application root.
+APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
+
+def system!(*args)
+ system(*args) || abort("\n== Command #{args} failed ==")
+end
+
+chdir APP_ROOT do
+ # This script is a starting point to setup your application.
+ # Add necessary setup steps to this file.
+
+ puts '== Installing dependencies =='
+ system! 'gem install bundler --conservative'
+ system('bundle check') || system!('bundle install')
+
+ # Install JavaScript dependencies if using Yarn
+ # system('bin/yarn')
+
+
+ # puts "\n== Copying sample files =="
+ # unless File.exist?('config/database.yml')
+ # cp 'config/database.yml.sample', 'config/database.yml'
+ # end
+
+ puts "\n== Preparing database =="
+ system! 'bin/rails db:setup'
+
+ puts "\n== Removing old logs and tempfiles =="
+ system! 'bin/rails log:clear tmp:clear'
+
+ puts "\n== Restarting application server =="
+ system! 'bin/rails restart'
+end
diff --git a/bin/spring b/bin/spring
new file mode 100755
index 0000000000..fb2ec2ebb4
--- /dev/null
+++ b/bin/spring
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+
+# This file loads spring without using Bundler, in order to be fast.
+# It gets overwritten when you run the `spring binstub` command.
+
+unless defined?(Spring)
+ require 'rubygems'
+ require 'bundler'
+
+ lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read)
+ spring = lockfile.specs.detect { |spec| spec.name == "spring" }
+ if spring
+ Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path
+ gem 'spring', spring.version
+ require 'spring/binstub'
+ end
+end
diff --git a/bin/update b/bin/update
new file mode 100755
index 0000000000..a8e4462f20
--- /dev/null
+++ b/bin/update
@@ -0,0 +1,29 @@
+#!/usr/bin/env ruby
+require 'pathname'
+require 'fileutils'
+include FileUtils
+
+# path to your application root.
+APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
+
+def system!(*args)
+ system(*args) || abort("\n== Command #{args} failed ==")
+end
+
+chdir APP_ROOT do
+ # This script is a way to update your development environment automatically.
+ # Add necessary update steps to this file.
+
+ puts '== Installing dependencies =='
+ system! 'gem install bundler --conservative'
+ system('bundle check') || system!('bundle install')
+
+ puts "\n== Updating database =="
+ system! 'bin/rails db:migrate'
+
+ puts "\n== Removing old logs and tempfiles =="
+ system! 'bin/rails log:clear tmp:clear'
+
+ puts "\n== Restarting application server =="
+ system! 'bin/rails restart'
+end
diff --git a/bin/yarn b/bin/yarn
new file mode 100755
index 0000000000..c2bacef836
--- /dev/null
+++ b/bin/yarn
@@ -0,0 +1,11 @@
+#!/usr/bin/env ruby
+VENDOR_PATH = File.expand_path('..', __dir__)
+Dir.chdir(VENDOR_PATH) do
+ begin
+ exec "yarnpkg #{ARGV.join(" ")}"
+ rescue Errno::ENOENT
+ $stderr.puts "Yarn executable was not detected in the system."
+ $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
+ exit 1
+ end
+end
diff --git a/config.ru b/config.ru
new file mode 100644
index 0000000000..f7ba0b527b
--- /dev/null
+++ b/config.ru
@@ -0,0 +1,5 @@
+# This file is used by Rack-based servers to start the application.
+
+require_relative 'config/environment'
+
+run Rails.application
diff --git a/config/application.rb b/config/application.rb
new file mode 100644
index 0000000000..5f6ca0f9b2
--- /dev/null
+++ b/config/application.rb
@@ -0,0 +1,25 @@
+require_relative 'boot'
+
+require 'rails/all'
+
+# Require the gems listed in Gemfile, including any gems
+# you've limited to :test, :development, or :production.
+Bundler.require(*Rails.groups)
+
+module Betsy
+ class Application < Rails::Application
+ config.generators do |g|
+ # Force new test files to be generated in the minitest-spec style
+ g.test_framework :minitest, spec: true
+
+ # Always use .js files, never .coffee
+ g.javascript_engine :js
+ end
+ # Initialize configuration defaults for originally generated Rails version.
+ config.load_defaults 5.1
+
+ # Settings in config/environments/* take precedence over those specified here.
+ # Application configuration should go into files in config/initializers
+ # -- all .rb files in that directory are automatically loaded.
+ end
+end
diff --git a/config/boot.rb b/config/boot.rb
new file mode 100644
index 0000000000..30f5120df6
--- /dev/null
+++ b/config/boot.rb
@@ -0,0 +1,3 @@
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
+
+require 'bundler/setup' # Set up gems listed in the Gemfile.
diff --git a/config/cable.yml b/config/cable.yml
new file mode 100644
index 0000000000..3cba994bb2
--- /dev/null
+++ b/config/cable.yml
@@ -0,0 +1,10 @@
+development:
+ adapter: async
+
+test:
+ adapter: async
+
+production:
+ adapter: redis
+ url: redis://localhost:6379/1
+ channel_prefix: betsy_production
diff --git a/config/database.yml b/config/database.yml
new file mode 100644
index 0000000000..6903bb6083
--- /dev/null
+++ b/config/database.yml
@@ -0,0 +1,85 @@
+# PostgreSQL. Versions 9.1 and up are supported.
+#
+# Install the pg driver:
+# gem install pg
+# On OS X with Homebrew:
+# gem install pg -- --with-pg-config=/usr/local/bin/pg_config
+# On OS X with MacPorts:
+# gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
+# On Windows:
+# gem install pg
+# Choose the win32 build.
+# Install PostgreSQL and put its /bin directory on your path.
+#
+# Configure Using Gemfile
+# gem 'pg'
+#
+default: &default
+ adapter: postgresql
+ encoding: unicode
+ # For details on connection pooling, see Rails configuration guide
+ # http://guides.rubyonrails.org/configuring.html#database-pooling
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
+
+development:
+ <<: *default
+ database: betsy_development
+
+ # The specified database role being used to connect to postgres.
+ # To create additional roles in postgres see `$ createuser --help`.
+ # When left blank, postgres will use the default role. This is
+ # the same name as the operating system user that initialized the database.
+ #username: betsy
+
+ # The password associated with the postgres role (username).
+ #password:
+
+ # Connect on a TCP socket. Omitted by default since the client uses a
+ # domain socket that doesn't need configuration. Windows does not have
+ # domain sockets, so uncomment these lines.
+ #host: localhost
+
+ # The TCP port the server listens on. Defaults to 5432.
+ # If your server runs on a different port number, change accordingly.
+ #port: 5432
+
+ # Schema search path. The server defaults to $user,public
+ #schema_search_path: myapp,sharedapp,public
+
+ # Minimum log levels, in increasing order:
+ # debug5, debug4, debug3, debug2, debug1,
+ # log, notice, warning, error, fatal, and panic
+ # Defaults to warning.
+ #min_messages: notice
+
+# Warning: The database defined as "test" will be erased and
+# re-generated from your development database when you run "rake".
+# Do not set this db to the same as development or production.
+test:
+ <<: *default
+ database: betsy_test
+
+# As with config/secrets.yml, you never want to store sensitive information,
+# like your database password, in your source code. If your source code is
+# ever seen by anyone, they now have access to your database.
+#
+# Instead, provide the password as a unix environment variable when you boot
+# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database
+# for a full rundown on how to provide these environment variables in a
+# production deployment.
+#
+# On Heroku and other platform providers, you may have a full connection URL
+# available as an environment variable. For example:
+#
+# DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"
+#
+# You can use this database configuration with:
+#
+# production:
+# url: <%= ENV['DATABASE_URL'] %>
+#
+production:
+ <<: *default
+ database: betsy_production
+ username: betsy
+ password: <%= ENV['BETSY_DATABASE_PASSWORD'] %>
diff --git a/config/environment.rb b/config/environment.rb
new file mode 100644
index 0000000000..426333bb46
--- /dev/null
+++ b/config/environment.rb
@@ -0,0 +1,5 @@
+# Load the Rails application.
+require_relative 'application'
+
+# Initialize the Rails application.
+Rails.application.initialize!
diff --git a/config/environments/development.rb b/config/environments/development.rb
new file mode 100644
index 0000000000..5187e22186
--- /dev/null
+++ b/config/environments/development.rb
@@ -0,0 +1,54 @@
+Rails.application.configure do
+ # Settings specified here will take precedence over those in config/application.rb.
+
+ # In the development environment your application's code is reloaded on
+ # every request. This slows down response time but is perfect for development
+ # since you don't have to restart the web server when you make code changes.
+ config.cache_classes = false
+
+ # Do not eager load code on boot.
+ config.eager_load = false
+
+ # Show full error reports.
+ config.consider_all_requests_local = true
+
+ # Enable/disable caching. By default caching is disabled.
+ if Rails.root.join('tmp/caching-dev.txt').exist?
+ config.action_controller.perform_caching = true
+
+ config.cache_store = :memory_store
+ config.public_file_server.headers = {
+ 'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}"
+ }
+ else
+ config.action_controller.perform_caching = false
+
+ config.cache_store = :null_store
+ end
+
+ # Don't care if the mailer can't send.
+ config.action_mailer.raise_delivery_errors = false
+
+ config.action_mailer.perform_caching = false
+
+ # Print deprecation notices to the Rails logger.
+ config.active_support.deprecation = :log
+
+ # Raise an error on page load if there are pending migrations.
+ config.active_record.migration_error = :page_load
+
+ # Debug mode disables concatenation and preprocessing of assets.
+ # This option may cause significant delays in view rendering with a large
+ # number of complex assets.
+ config.assets.debug = true
+
+ # Suppress logger output for asset requests.
+ config.assets.quiet = true
+
+ # Raises error for missing translations
+ # config.action_view.raise_on_missing_translations = true
+
+ # Use an evented file watcher to asynchronously detect changes in source code,
+ # routes, locales, etc. This feature depends on the listen gem.
+ config.file_watcher = ActiveSupport::EventedFileUpdateChecker
+end
diff --git a/config/environments/production.rb b/config/environments/production.rb
new file mode 100644
index 0000000000..9284f84839
--- /dev/null
+++ b/config/environments/production.rb
@@ -0,0 +1,91 @@
+Rails.application.configure do
+ # Settings specified here will take precedence over those in config/application.rb.
+
+ # Code is not reloaded between requests.
+ config.cache_classes = true
+
+ # Eager load code on boot. This eager loads most of Rails and
+ # your application in memory, allowing both threaded web servers
+ # and those relying on copy on write to perform better.
+ # Rake tasks automatically ignore this option for performance.
+ config.eager_load = true
+
+ # Full error reports are disabled and caching is turned on.
+ config.consider_all_requests_local = false
+ config.action_controller.perform_caching = true
+
+ # Attempt to read encrypted secrets from `config/secrets.yml.enc`.
+ # Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or
+ # `config/secrets.yml.key`.
+ config.read_encrypted_secrets = true
+
+ # Disable serving static files from the `/public` folder by default since
+ # Apache or NGINX already handles this.
+ config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
+
+ # Compress JavaScripts and CSS.
+ config.assets.js_compressor = :uglifier
+ # config.assets.css_compressor = :sass
+
+ # Do not fallback to assets pipeline if a precompiled asset is missed.
+ config.assets.compile = false
+
+ # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
+
+ # Enable serving of images, stylesheets, and JavaScripts from an asset server.
+ # config.action_controller.asset_host = 'http://assets.example.com'
+
+ # Specifies the header that your server uses for sending files.
+ # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
+ # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
+
+ # Mount Action Cable outside main process or domain
+ # config.action_cable.mount_path = nil
+ # config.action_cable.url = 'wss://example.com/cable'
+ # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
+
+ # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
+ # config.force_ssl = true
+
+ # Use the lowest log level to ensure availability of diagnostic information
+ # when problems arise.
+ config.log_level = :debug
+
+ # Prepend all log lines with the following tags.
+ config.log_tags = [ :request_id ]
+
+ # Use a different cache store in production.
+ # config.cache_store = :mem_cache_store
+
+ # Use a real queuing backend for Active Job (and separate queues per environment)
+ # config.active_job.queue_adapter = :resque
+ # config.active_job.queue_name_prefix = "betsy_#{Rails.env}"
+ config.action_mailer.perform_caching = false
+
+ # Ignore bad email addresses and do not raise email delivery errors.
+ # Set this to true and configure the email server for immediate delivery to raise delivery errors.
+ # config.action_mailer.raise_delivery_errors = false
+
+ # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
+ # the I18n.default_locale when a translation cannot be found).
+ config.i18n.fallbacks = true
+
+ # Send deprecation notices to registered listeners.
+ config.active_support.deprecation = :notify
+
+ # Use default logging formatter so that PID and timestamp are not suppressed.
+ config.log_formatter = ::Logger::Formatter.new
+
+ # Use a different logger for distributed setups.
+ # require 'syslog/logger'
+ # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
+
+ if ENV["RAILS_LOG_TO_STDOUT"].present?
+ logger = ActiveSupport::Logger.new(STDOUT)
+ logger.formatter = config.log_formatter
+ config.logger = ActiveSupport::TaggedLogging.new(logger)
+ end
+
+ # Do not dump schema after migrations.
+ config.active_record.dump_schema_after_migration = false
+end
diff --git a/config/environments/test.rb b/config/environments/test.rb
new file mode 100644
index 0000000000..8e5cbde533
--- /dev/null
+++ b/config/environments/test.rb
@@ -0,0 +1,42 @@
+Rails.application.configure do
+ # Settings specified here will take precedence over those in config/application.rb.
+
+ # The test environment is used exclusively to run your application's
+ # test suite. You never need to work with it otherwise. Remember that
+ # your test database is "scratch space" for the test suite and is wiped
+ # and recreated between test runs. Don't rely on the data there!
+ config.cache_classes = true
+
+ # Do not eager load code on boot. This avoids loading your whole application
+ # just for the purpose of running a single test. If you are using a tool that
+ # preloads Rails for running tests, you may have to set it to true.
+ config.eager_load = false
+
+ # Configure public file server for tests with Cache-Control for performance.
+ config.public_file_server.enabled = true
+ config.public_file_server.headers = {
+ 'Cache-Control' => "public, max-age=#{1.hour.seconds.to_i}"
+ }
+
+ # Show full error reports and disable caching.
+ config.consider_all_requests_local = true
+ config.action_controller.perform_caching = false
+
+ # Raise exceptions instead of rendering exception templates.
+ config.action_dispatch.show_exceptions = false
+
+ # Disable request forgery protection in test environment.
+ config.action_controller.allow_forgery_protection = false
+ config.action_mailer.perform_caching = false
+
+ # Tell Action Mailer not to deliver emails to the real world.
+ # The :test delivery method accumulates sent emails in the
+ # ActionMailer::Base.deliveries array.
+ config.action_mailer.delivery_method = :test
+
+ # Print deprecation notices to the stderr.
+ config.active_support.deprecation = :stderr
+
+ # Raises error for missing translations
+ # config.action_view.raise_on_missing_translations = true
+end
diff --git a/config/initializers/application_controller_renderer.rb b/config/initializers/application_controller_renderer.rb
new file mode 100644
index 0000000000..89d2efab2b
--- /dev/null
+++ b/config/initializers/application_controller_renderer.rb
@@ -0,0 +1,8 @@
+# Be sure to restart your server when you modify this file.
+
+# ActiveSupport::Reloader.to_prepare do
+# ApplicationController.renderer.defaults.merge!(
+# http_host: 'example.org',
+# https: false
+# )
+# end
diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb
new file mode 100644
index 0000000000..4b828e80cb
--- /dev/null
+++ b/config/initializers/assets.rb
@@ -0,0 +1,14 @@
+# Be sure to restart your server when you modify this file.
+
+# Version of your assets, change this if you want to expire all your assets.
+Rails.application.config.assets.version = '1.0'
+
+# Add additional assets to the asset load path.
+# Rails.application.config.assets.paths << Emoji.images_path
+# Add Yarn node_modules folder to the asset load path.
+Rails.application.config.assets.paths << Rails.root.join('node_modules')
+
+# Precompile additional assets.
+# application.js, application.css, and all non-JS/CSS in the app/assets
+# folder are already added.
+# Rails.application.config.assets.precompile += %w( admin.js admin.css )
diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb
new file mode 100644
index 0000000000..59385cdf37
--- /dev/null
+++ b/config/initializers/backtrace_silencers.rb
@@ -0,0 +1,7 @@
+# Be sure to restart your server when you modify this file.
+
+# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
+# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
+
+# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
+# Rails.backtrace_cleaner.remove_silencers!
diff --git a/config/initializers/cookies_serializer.rb b/config/initializers/cookies_serializer.rb
new file mode 100644
index 0000000000..5a6a32d371
--- /dev/null
+++ b/config/initializers/cookies_serializer.rb
@@ -0,0 +1,5 @@
+# Be sure to restart your server when you modify this file.
+
+# Specify a serializer for the signed and encrypted cookie jars.
+# Valid options are :json, :marshal, and :hybrid.
+Rails.application.config.action_dispatch.cookies_serializer = :json
diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb
new file mode 100644
index 0000000000..4a994e1e7b
--- /dev/null
+++ b/config/initializers/filter_parameter_logging.rb
@@ -0,0 +1,4 @@
+# Be sure to restart your server when you modify this file.
+
+# Configure sensitive parameters which will be filtered from the log file.
+Rails.application.config.filter_parameters += [:password]
diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb
new file mode 100644
index 0000000000..ac033bf9dc
--- /dev/null
+++ b/config/initializers/inflections.rb
@@ -0,0 +1,16 @@
+# Be sure to restart your server when you modify this file.
+
+# Add new inflection rules using the following format. Inflections
+# are locale specific, and you may define rules for as many different
+# locales as you wish. All of these examples are active by default:
+# ActiveSupport::Inflector.inflections(:en) do |inflect|
+# inflect.plural /^(ox)$/i, '\1en'
+# inflect.singular /^(ox)en/i, '\1'
+# inflect.irregular 'person', 'people'
+# inflect.uncountable %w( fish sheep )
+# end
+
+# These inflection rules are supported but not enabled by default:
+# ActiveSupport::Inflector.inflections(:en) do |inflect|
+# inflect.acronym 'RESTful'
+# end
diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb
new file mode 100644
index 0000000000..dc1899682b
--- /dev/null
+++ b/config/initializers/mime_types.rb
@@ -0,0 +1,4 @@
+# Be sure to restart your server when you modify this file.
+
+# Add new mime types for use in respond_to blocks:
+# Mime::Type.register "text/richtext", :rtf
diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb
new file mode 100644
index 0000000000..fd4416122a
--- /dev/null
+++ b/config/initializers/omniauth.rb
@@ -0,0 +1,3 @@
+Rails.application.config.middleware.use OmniAuth::Builder do
+ provider :github, ENV["GITHUB_CLIENT_ID"], ENV["GITHUB_CLIENT_SECRET"], scope: "user:email"
+end
diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb
new file mode 100644
index 0000000000..bbfc3961bf
--- /dev/null
+++ b/config/initializers/wrap_parameters.rb
@@ -0,0 +1,14 @@
+# Be sure to restart your server when you modify this file.
+
+# This file contains settings for ActionController::ParamsWrapper which
+# is enabled by default.
+
+# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
+ActiveSupport.on_load(:action_controller) do
+ wrap_parameters format: [:json]
+end
+
+# To enable root element in JSON for ActiveRecord objects.
+# ActiveSupport.on_load(:active_record) do
+# self.include_root_in_json = true
+# end
diff --git a/config/locales/en.yml b/config/locales/en.yml
new file mode 100644
index 0000000000..decc5a8573
--- /dev/null
+++ b/config/locales/en.yml
@@ -0,0 +1,33 @@
+# Files in the config/locales directory are used for internationalization
+# and are automatically loaded by Rails. If you want to use locales other
+# than English, add the necessary files in this directory.
+#
+# To use the locales, use `I18n.t`:
+#
+# I18n.t 'hello'
+#
+# In views, this is aliased to just `t`:
+#
+# <%= t('hello') %>
+#
+# To use a different locale, set it with `I18n.locale`:
+#
+# I18n.locale = :es
+#
+# This would use the information in config/locales/es.yml.
+#
+# The following keys must be escaped otherwise they will not be retrieved by
+# the default I18n backend:
+#
+# true, false, on, off, yes, no
+#
+# Instead, surround them with single quotes.
+#
+# en:
+# 'true': 'foo'
+#
+# To learn more, please read the Rails Internationalization guide
+# available at http://guides.rubyonrails.org/i18n.html.
+
+en:
+ hello: "Hello world"
diff --git a/config/puma.rb b/config/puma.rb
new file mode 100644
index 0000000000..1e19380dcb
--- /dev/null
+++ b/config/puma.rb
@@ -0,0 +1,56 @@
+# Puma can serve each request in a thread from an internal thread pool.
+# The `threads` method setting takes two numbers: a minimum and maximum.
+# Any libraries that use thread pools should be configured to match
+# the maximum value specified for Puma. Default is set to 5 threads for minimum
+# and maximum; this matches the default thread size of Active Record.
+#
+threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
+threads threads_count, threads_count
+
+# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
+#
+port ENV.fetch("PORT") { 3000 }
+
+# Specifies the `environment` that Puma will run in.
+#
+environment ENV.fetch("RAILS_ENV") { "development" }
+
+# Specifies the number of `workers` to boot in clustered mode.
+# Workers are forked webserver processes. If using threads and workers together
+# the concurrency of the application would be max `threads` * `workers`.
+# Workers do not work on JRuby or Windows (both of which do not support
+# processes).
+#
+# workers ENV.fetch("WEB_CONCURRENCY") { 2 }
+
+# Use the `preload_app!` method when specifying a `workers` number.
+# This directive tells Puma to first boot the application and load code
+# before forking the application. This takes advantage of Copy On Write
+# process behavior so workers use less memory. If you use this option
+# you need to make sure to reconnect any threads in the `on_worker_boot`
+# block.
+#
+# preload_app!
+
+# If you are preloading your application and using Active Record, it's
+# recommended that you close any connections to the database before workers
+# are forked to prevent connection leakage.
+#
+# before_fork do
+# ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord)
+# end
+
+# The code in the `on_worker_boot` will be called if you are using
+# clustered mode by specifying a number of `workers`. After each worker
+# process is booted, this block will be run. If you are using the `preload_app!`
+# option, you will want to use this block to reconnect to any threads
+# or connections that may have been created at application boot, as Ruby
+# cannot share connections between processes.
+#
+# on_worker_boot do
+# ActiveRecord::Base.establish_connection if defined?(ActiveRecord)
+# end
+#
+
+# Allow puma to be restarted by `rails restart` command.
+plugin :tmp_restart
diff --git a/config/routes.rb b/config/routes.rb
new file mode 100644
index 0000000000..568b4d3a00
--- /dev/null
+++ b/config/routes.rb
@@ -0,0 +1,41 @@
+Rails.application.routes.draw do
+ # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
+ root 'products#root'
+
+ resources :orders, only: [:index, :show, :edit, :update, :destroy] do
+ get 'receipt'
+ get 'empty_cart'
+ end
+
+ get 'orders/:id/checkout', to: 'orders#checkout', as: 'checkout'
+
+
+ resources :products do
+ resources :reviews, only: [:new]
+ end
+ patch '/products/:id/retire', to: 'products#retire', as: 'retire_product'
+
+ resources :reviews, only: [:new, :create]
+ resources :merchants, only: [:index, :create, :show, :destroy]
+
+ resources :order_products, only: [:edit, :update, :destroy]
+ post '/order_products', to: 'order_products#create', as: 'create_order_product'
+ patch '/order_products/:id/update_status', to: 'order_products#update_status', as: 'update_status'
+
+
+ get "/auth/:provider/callback", to: "merchants#create", as: 'auth_callback'
+ get '/logout', to: 'merchants#logout', as: 'logout'
+
+ # get "/categories", to: 'categories#index', as: 'categories'
+ # get "/categories/new", to: 'categories#new', as: 'new_category'
+ # post "/categories", to: 'categories#create'
+
+ # resources :categories, only: [:index, :new, :create]
+
+ resources :categories do
+ # get '/products', to: 'products#index'
+ resources :products, only: [:index, :new, :create]
+ end
+
+
+end
diff --git a/config/secrets.yml b/config/secrets.yml
new file mode 100644
index 0000000000..c576395ae6
--- /dev/null
+++ b/config/secrets.yml
@@ -0,0 +1,32 @@
+# Be sure to restart your server when you modify this file.
+
+# Your secret key is used for verifying the integrity of signed cookies.
+# If you change this key, all old signed cookies will become invalid!
+
+# Make sure the secret is at least 30 characters and all random,
+# no regular words or you'll be exposed to dictionary attacks.
+# You can use `rails secret` to generate a secure secret key.
+
+# Make sure the secrets in this file are kept private
+# if you're sharing your code publicly.
+
+# Shared secrets are available across all environments.
+
+# shared:
+# api_key: a1B2c3D4e5F6
+
+# Environmental secrets are only available for that specific environment.
+
+development:
+ secret_key_base: 6e5982597de3c024cbc2510aaf226317bcc2061b0ba06d6213d308163ee16096bfe32aec74458b2ad9f51d5746db85b5fead79571b817df7fb44f1ee0e71220b
+
+test:
+ secret_key_base: 2d7d0e75ee18088f964f7b2374257690106347fe802b712489be93b1dc4e9813e476117e1190dee17c6069ce8a8be86d3302b276b58388b7428c5846acf7333e
+
+# Do not keep production secrets in the unencrypted secrets file.
+# Instead, either read values from the environment.
+# Or, use `bin/rails secrets:setup` to configure encrypted secrets
+# and move the `production:` environment over there.
+
+production:
+ secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
diff --git a/config/spring.rb b/config/spring.rb
new file mode 100644
index 0000000000..c9119b40c0
--- /dev/null
+++ b/config/spring.rb
@@ -0,0 +1,6 @@
+%w(
+ .ruby-version
+ .rbenv-vars
+ tmp/restart.txt
+ tmp/caching-dev.txt
+).each { |path| Spring.watch(path) }
diff --git a/db/migrate/20171017225535_create_products.rb b/db/migrate/20171017225535_create_products.rb
new file mode 100644
index 0000000000..ba4a013b74
--- /dev/null
+++ b/db/migrate/20171017225535_create_products.rb
@@ -0,0 +1,15 @@
+class CreateProducts < ActiveRecord::Migration[5.1]
+ def change
+ create_table :products do |t|
+ t.string :name
+ t.text :description
+ t.integer :price
+ t.integer :merchant_id
+ t.string :inventory
+ t.string :photo_url
+
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20171017225858_create_orders.rb b/db/migrate/20171017225858_create_orders.rb
new file mode 100644
index 0000000000..7bbcee867c
--- /dev/null
+++ b/db/migrate/20171017225858_create_orders.rb
@@ -0,0 +1,16 @@
+class CreateOrders < ActiveRecord::Migration[5.1]
+ def change
+ create_table :orders do |t|
+ t.string :status
+ t.string :email
+ t.string :mailing_address
+ t.string :buyer_name
+ t.string :card_number
+ t.string :expiration
+ t.string :cvv
+ t.string :zipcode
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20171017230617_create_merchants.rb b/db/migrate/20171017230617_create_merchants.rb
new file mode 100644
index 0000000000..64a57c904c
--- /dev/null
+++ b/db/migrate/20171017230617_create_merchants.rb
@@ -0,0 +1,10 @@
+class CreateMerchants < ActiveRecord::Migration[5.1]
+ def change
+ create_table :merchants do |t|
+ t.string :username
+ t.string :email
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20171018023503_change_product_price_from_intege_to_float.rb b/db/migrate/20171018023503_change_product_price_from_intege_to_float.rb
new file mode 100644
index 0000000000..246692c6c3
--- /dev/null
+++ b/db/migrate/20171018023503_change_product_price_from_intege_to_float.rb
@@ -0,0 +1,6 @@
+class ChangeProductPriceFromIntegeToFloat < ActiveRecord::Migration[5.1]
+ def change
+ remove_column :products, :price
+ add_column :products, :price, :float
+ end
+end
diff --git a/db/migrate/20171018185635_create_reviews.rb b/db/migrate/20171018185635_create_reviews.rb
new file mode 100644
index 0000000000..4cfc2a3d29
--- /dev/null
+++ b/db/migrate/20171018185635_create_reviews.rb
@@ -0,0 +1,11 @@
+class CreateReviews < ActiveRecord::Migration[5.1]
+ def change
+ create_table :reviews do |t|
+ t.integer :rating
+ t.string :text
+ t.integer :product_id
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20171018192530_create_order_products.rb b/db/migrate/20171018192530_create_order_products.rb
new file mode 100644
index 0000000000..61e3e5eae6
--- /dev/null
+++ b/db/migrate/20171018192530_create_order_products.rb
@@ -0,0 +1,11 @@
+class CreateOrderProducts < ActiveRecord::Migration[5.1]
+ def change
+ create_table :order_products do |t|
+ t.integer :quantity
+ t.integer :product_id
+ t.integer :order_id
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20171019005522_add_columns_to_merchants.rb b/db/migrate/20171019005522_add_columns_to_merchants.rb
new file mode 100644
index 0000000000..0ca18f4ea4
--- /dev/null
+++ b/db/migrate/20171019005522_add_columns_to_merchants.rb
@@ -0,0 +1,7 @@
+class AddColumnsToMerchants < ActiveRecord::Migration[5.1]
+ def change
+ add_column :merchants, :name, :string
+ add_column :merchants, :provider, :string, null: false
+ add_column :merchants, :uid, :string, null: false
+ end
+end
diff --git a/db/migrate/20171020013202_change_product_inventory_to_integer.rb b/db/migrate/20171020013202_change_product_inventory_to_integer.rb
new file mode 100644
index 0000000000..2edbcf0a4d
--- /dev/null
+++ b/db/migrate/20171020013202_change_product_inventory_to_integer.rb
@@ -0,0 +1,6 @@
+class ChangeProductInventoryToInteger < ActiveRecord::Migration[5.1]
+ def change
+ change_column(:products, :inventory, 'integer USING CAST(inventory AS integer)')
+
+ end
+end
diff --git a/db/migrate/20171020192401_create_categories.rb b/db/migrate/20171020192401_create_categories.rb
new file mode 100644
index 0000000000..6a23464847
--- /dev/null
+++ b/db/migrate/20171020192401_create_categories.rb
@@ -0,0 +1,9 @@
+class CreateCategories < ActiveRecord::Migration[5.1]
+ def change
+ create_table :categories do |t|
+ t.string :name
+ t.timestamps
+ end
+ create_join_table :products, :categories
+ end
+end
diff --git a/db/migrate/20171024031744_create_payment_infos.rb b/db/migrate/20171024031744_create_payment_infos.rb
new file mode 100644
index 0000000000..2ae19ae802
--- /dev/null
+++ b/db/migrate/20171024031744_create_payment_infos.rb
@@ -0,0 +1,15 @@
+class CreatePaymentInfos < ActiveRecord::Migration[5.1]
+ def change
+ create_table :payment_infos do |t|
+ t.string :email
+ t.string :mailing_address
+ t.string :buyer_name
+ t.string :card_number
+ t.string :expiration
+ t.string :cvv
+ t.string :zipcode
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20171024031934_remove_payment_info_from_order.rb b/db/migrate/20171024031934_remove_payment_info_from_order.rb
new file mode 100644
index 0000000000..20f5dc0b7d
--- /dev/null
+++ b/db/migrate/20171024031934_remove_payment_info_from_order.rb
@@ -0,0 +1,11 @@
+class RemovePaymentInfoFromOrder < ActiveRecord::Migration[5.1]
+ def change
+ remove_column :orders, :email
+ remove_column :orders, :mailing_address
+ remove_column :orders, :buyer_name
+ remove_column :orders, :card_number
+ remove_column :orders, :expiration
+ remove_column :orders, :cvv
+ remove_column :orders, :zipcode
+ end
+end
diff --git a/db/migrate/20171024032510_add_order_id_to_payment_info.rb b/db/migrate/20171024032510_add_order_id_to_payment_info.rb
new file mode 100644
index 0000000000..c2774769af
--- /dev/null
+++ b/db/migrate/20171024032510_add_order_id_to_payment_info.rb
@@ -0,0 +1,6 @@
+class AddOrderIdToPaymentInfo < ActiveRecord::Migration[5.1]
+ def change
+ add_column :payment_infos, :order_id, :integer
+ add_column :orders, :payment_info_id, :integer
+ end
+end
diff --git a/db/migrate/20171024175026_add_status_to_op.rb b/db/migrate/20171024175026_add_status_to_op.rb
new file mode 100644
index 0000000000..f6c638450e
--- /dev/null
+++ b/db/migrate/20171024175026_add_status_to_op.rb
@@ -0,0 +1,5 @@
+class AddStatusToOp < ActiveRecord::Migration[5.1]
+ def change
+ add_column :order_products, :status, :string
+ end
+end
diff --git a/db/migrate/20171024212310_add_retired_to.rb b/db/migrate/20171024212310_add_retired_to.rb
new file mode 100644
index 0000000000..0dd686391b
--- /dev/null
+++ b/db/migrate/20171024212310_add_retired_to.rb
@@ -0,0 +1,5 @@
+class AddRetiredTo < ActiveRecord::Migration[5.1]
+ def change
+ add_column :products, :retired, :boolean
+ end
+end
diff --git a/db/migrate/20171025181747_add_default_value_to_retired.rb b/db/migrate/20171025181747_add_default_value_to_retired.rb
new file mode 100644
index 0000000000..bc371f865c
--- /dev/null
+++ b/db/migrate/20171025181747_add_default_value_to_retired.rb
@@ -0,0 +1,5 @@
+class AddDefaultValueToRetired < ActiveRecord::Migration[5.1]
+ def change
+ change_column :products, :retired, :boolean, :default => false
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
new file mode 100644
index 0000000000..25444b4276
--- /dev/null
+++ b/db/schema.rb
@@ -0,0 +1,88 @@
+# This file is auto-generated from the current state of the database. Instead
+# of editing this file, please use the migrations feature of Active Record to
+# incrementally modify your database, and then regenerate this schema definition.
+#
+# Note that this schema.rb definition is the authoritative source for your
+# database schema. If you need to create the application database on another
+# system, you should be using db:schema:load, not running all the migrations
+# from scratch. The latter is a flawed and unsustainable approach (the more migrations
+# you'll amass, the slower it'll run and the greater likelihood for issues).
+#
+# It's strongly recommended that you check this file into your version control system.
+
+ActiveRecord::Schema.define(version: 20171025181747) do
+
+ # These are extensions that must be enabled in order to support this database
+ enable_extension "plpgsql"
+
+ create_table "categories", force: :cascade do |t|
+ t.string "name"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+ create_table "categories_products", id: false, force: :cascade do |t|
+ t.bigint "product_id", null: false
+ t.bigint "category_id", null: false
+ end
+
+ create_table "merchants", force: :cascade do |t|
+ t.string "username"
+ t.string "email"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.string "name"
+ t.string "provider", null: false
+ t.string "uid", null: false
+ end
+
+ create_table "order_products", force: :cascade do |t|
+ t.integer "quantity"
+ t.integer "product_id"
+ t.integer "order_id"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.string "status"
+ end
+
+ create_table "orders", force: :cascade do |t|
+ t.string "status"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.integer "payment_info_id"
+ end
+
+ create_table "payment_infos", force: :cascade do |t|
+ t.string "email"
+ t.string "mailing_address"
+ t.string "buyer_name"
+ t.string "card_number"
+ t.string "expiration"
+ t.string "cvv"
+ t.string "zipcode"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.integer "order_id"
+ end
+
+ create_table "products", force: :cascade do |t|
+ t.string "name"
+ t.text "description"
+ t.integer "merchant_id"
+ t.integer "inventory"
+ t.string "photo_url"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.float "price"
+ t.boolean "retired", default: false
+ end
+
+ create_table "reviews", force: :cascade do |t|
+ t.integer "rating"
+ t.string "text"
+ t.integer "product_id"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+end
diff --git a/db/seed_data/categories.csv b/db/seed_data/categories.csv
new file mode 100644
index 0000000000..f3c17e6c84
--- /dev/null
+++ b/db/seed_data/categories.csv
@@ -0,0 +1,7 @@
+name
+halloween
+music
+food
+animal
+game
+book
diff --git a/db/seed_data/merchants.csv b/db/seed_data/merchants.csv
new file mode 100644
index 0000000000..dfe9de5cfe
--- /dev/null
+++ b/db/seed_data/merchants.csv
@@ -0,0 +1,5 @@
+name,username,email,provider,uid
+Bennett Rahn,bennettrahn,rahnibennett@gmail.com,github,26212537
+Ben Merchant,benmerchant41,benmerchant41@gmail.com,github,32968600
+Lauren Lee,laurenelee,laurenelee88@gmail.com,github,24926734
+Anders Chen ,anderschenders,andreachen.ac@gmail.com,github,21146738
diff --git a/db/seed_data/products.csv b/db/seed_data/products.csv
new file mode 100644
index 0000000000..16571b396b
--- /dev/null
+++ b/db/seed_data/products.csv
@@ -0,0 +1,12 @@
+name,inventory,price,photo_url,description,merchant_id,category
+Destiny's Child,3,10.5,http://cdn.playbuzz.com/cdn/e880452f-2f4e-44d5-8b62-5ad9ebcec66a/222b50e6-cb8a-4b3f-8293-b742778c04f9.jpg,A classic album!,1,2
+TLC ,10,11,http://www.kiss925.com/wp-content/uploads/sites/59/2015/03/tlc.jpg,A great debate between Destiny's Child and TLC... buy today to decide for yourself,2,2
+Hanson,5,11,https://cps-static.rovicorp.com/3/JPG_250/MI0002/296/MI0002296059.jpg?partner=allrovi.com,Three adorable young men,3,2
+BLT,10,5.5,http://hagerstownpizzabrothers.com/wp-content/uploads/2015/02/BLT-Sandwich.jpg,Delicious dinner or lunch!,4,3
+Neapolitan Ice Cream,3,3,http://www.articlesweb.org/blog/wp-content/uploads/2011/11/neapolitan-ice-cream-origin-and-recipe-sources-4.jpg,Scrumptious! ,1,3
+Kangaroo,1,100,http://www.australia.com/etc/designs/tourismaustralia/clientlibs/imgs/fallback/kangaroo_800_600.jpg,A hilarious and cute animal that sort of has three legs!,2,4
+Rock Paper Scissors,1,0.5,https://thenypost.files.wordpress.com/2014/06/rock-paper-4.jpg,A game that has 3 options!,3,5
+Movie,3,15,http://popcrush.com/files/2014/09/HocusPocus.jpg,A halloween classic,4,1
+Three Little Pigs,5,2,"https://images-na.ssl-images-amazon.com/images/I/51YKtd0IuZL._SX258_BO1,204,203,200_.jpg",A childhood hit,1,6
+Powerpuff Girls,3,30,https://img0.etsystatic.com/021/0/6191082/il_570xN.498434840_391z.jpg,A fun costume!,2,1
+Beetlejuice,3,12,https://i.pinimg.com/736x/2e/bc/65/2ebc65a661df3da311294af9b4e33ea7--beetlejuice-movie-beetlejuice-costume.jpg,A halloween fun and scary hit!,3,1
diff --git a/db/seeds.rb b/db/seeds.rb
new file mode 100644
index 0000000000..02f457551c
--- /dev/null
+++ b/db/seeds.rb
@@ -0,0 +1,182 @@
+# This file should contain all the record creation needed to seed the database with its default values.
+# The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
+#
+# Examples:
+#
+# movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
+# Character.create(name: 'Luke', movie: movies.first)
+require 'csv'
+
+# MERCHANTS #
+
+MERCHANT_FILE = Rails.root.join('db','seed_data','merchants.csv')
+puts "Loading raw media data from #{MERCHANT_FILE}"
+
+merchant_failures = []
+CSV.foreach(MERCHANT_FILE, :headers => true) do |row|
+ merchant = Merchant.new
+ merchant.name = row['name']
+ merchant.username = row['username']
+ merchant.email = row['email']
+ merchant.provider = row['provider']
+ merchant.uid = row['uid']
+ puts "Created merchant: #{merchant.inspect}"
+ successful = merchant.save
+ if !successful
+ merchant_failures << merchant
+ end
+end
+
+puts "Added #{Merchant.count} merchant records"
+puts "#{merchant_failures.length} merchants failed to save"
+
+# CATEGORIES #
+
+CATEGORY_FILE = Rails.root.join('db','seed_data','categories.csv')
+puts "Loading raw media data from #{CATEGORY_FILE}"
+
+category_failures = []
+CSV.foreach(CATEGORY_FILE, :headers => true) do |row|
+ category = Category.new
+ category.name = row['name']
+ puts "Created category: #{category.inspect}"
+ successful = category.save
+ if !successful
+ category_failures << category
+ end
+end
+
+puts "Added #{Category.count} category records"
+puts "#{category_failures.length} categories failed to save"
+
+# PRODUCT CATEGORIES #
+
+# PC_FILE = Rails.root.join('db','seed_data','product_category.csv')
+# puts "Loading raw media data from #{PC_FILE}"
+#
+# product_category_failures = []
+# CSV.foreach(PC_FILE, :headers => true) do |row|
+# product_category = ProductCategory.new
+# product_category.product_id = row['product_id']
+# product_category.category_id = row['category_id']
+# puts "Created merchant: #{product_category.inspect}"
+# successful = product_category.save
+# if !successful
+# product_category_failures << product_category
+# end
+# end
+#
+# puts "Added #{ProductCategory.count} product_category records"
+# puts "#{product_category_failures.length} product_category failed to save"
+
+# PRODUCTS #
+
+PRODUCT_FILE = Rails.root.join('db','seed_data','products.csv')
+puts "Loading raw media data from #{PRODUCT_FILE}"
+
+product_failures = []
+CSV.foreach(PRODUCT_FILE, :headers => true) do |row|
+ product = Product.new
+ product.name = row['name']
+ product.price = row['price']
+ product.inventory = row['inventory']
+ product.photo_url = row['photo_url']
+ product.description = row['description']
+ product.merchant_id = row['merchant_id']
+ product.category_ids = [row['category']]
+ puts "Created product: #{product.inspect}"
+ successful = product.save
+ if !successful
+ product_failures << product
+ end
+end
+
+puts "Added #{Product.count} product records"
+puts "#{product_failures.length} productd failed to save"
+
+# REVIEWS #
+
+# REVIEW_FILE = Rails.root.join('db','seed_data','review.csv')
+# puts "Loading raw media data from #{REVIEW_FILE}"
+#
+# review_failures = []
+# CSV.foreach(REVIEW_FILE, :headers => true) do |row|
+# review = Review.new
+# review.review = row['review']
+# review.rating = row['rating']
+# review.product_id = row['product']
+# puts "Created review: #{review.inspect}"
+# successful = review.save
+# if !successful
+# review_failures << review
+# end
+# end
+#
+# puts "Added #{Review.count} review records"
+# puts "#{review_failures.length} reviews failed to save"
+
+
+# ORDER ITEMS #
+
+# order_failures = []
+# 10.times do
+# order = Order.new
+# successful = order.save
+# if !successful
+# order_failures << order_item
+# end
+# puts "Created order: #{order.inspect}"
+# end
+# puts "Added #{Order.count} order item records"
+# puts "#{order_failures.length} orders failed to save"
+
+# ORDER ITEMS #
+
+# ORDER_ITEMS_FILE = Rails.root.join('db','seed_data','order_items.csv')
+# puts "Loading raw media data from #{ORDER_ITEMS_FILE}"
+#
+# order_items_failures = []
+# CSV.foreach(ORDER_ITEMS_FILE, :headers => true) do |row|
+# order_item = OrderItem.new
+# order_item.product_id = row['product_id']
+# order_item.order_id = row['order_id']
+# order_item.quantity = row['quantity']
+#
+# puts "Created order item: #{order_item.inspect}"
+# successful = order_item.save
+# if !successful
+# order_items_failures << order_item
+# end
+# end
+#
+# puts "Added #{OrderItem.count} order item records"
+# puts "#{order_items_failures.length} order items failed to save"
+
+# Payments #
+
+# PAYMENT_FILE = Rails.root.join('db','seed_data','payment.csv')
+# puts "Loading raw payment data from #{PAYMENT_FILE}"
+#
+# d1 = Date.new(2017,5,8)
+#
+# payment_failures = []
+# CSV.foreach(PAYMENT_FILE, :headers => true) do |row|
+# payment = Payment.new
+# payment.email = row['email']
+# payment.mailing_address = row['mailing_address']
+# payment.cc_name = row['cc_name']
+# payment.cc_expiration = d1
+# payment.cc_number = row['cc_number']
+# payment.cc_ccv = row['cc_ccv']
+# payment.billing_zip = row['billing_zip']
+# payment.order_id = row['order_id']
+#
+# puts "Created payment: #{payment.inspect}"
+# successful = payment.save
+# if !successful
+# payment_failures << payment
+# end
+# end
+#
+# puts "Added #{Payment.count} order item records"
+# puts "#{payment_failures.length} payments failed to save"
diff --git a/lib/assets/.keep b/lib/assets/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/lib/tasks/.keep b/lib/tasks/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/log/.keep b/log/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/package.json b/package.json
new file mode 100644
index 0000000000..f874acf437
--- /dev/null
+++ b/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "betsy",
+ "private": true,
+ "dependencies": {}
+}
diff --git a/public/404.html b/public/404.html
new file mode 100644
index 0000000000..2be3af26fc
--- /dev/null
+++ b/public/404.html
@@ -0,0 +1,67 @@
+
+
+
+ The page you were looking for doesn't exist (404)
+
+
+
+
+
+
+
+
+
The page you were looking for doesn't exist.
+
You may have mistyped the address or the page may have moved.
+
+
If you are the application owner check the logs for more information.
+
+
+
diff --git a/public/422.html b/public/422.html
new file mode 100644
index 0000000000..c08eac0d1d
--- /dev/null
+++ b/public/422.html
@@ -0,0 +1,67 @@
+
+
+
+ The change you wanted was rejected (422)
+
+
+
+
+
+
+
+
+
The change you wanted was rejected.
+
Maybe you tried to change something you didn't have access to.
+
+
If you are the application owner check the logs for more information.
+
+
+
diff --git a/public/500.html b/public/500.html
new file mode 100644
index 0000000000..78a030af22
--- /dev/null
+++ b/public/500.html
@@ -0,0 +1,66 @@
+
+
+
+ We're sorry, but something went wrong (500)
+
+
+
+
+
+
+
+
+
We're sorry, but something went wrong.
+
+
If you are the application owner check the logs for more information.
+
+
+
diff --git a/public/apple-touch-icon-precomposed.png b/public/apple-touch-icon-precomposed.png
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/public/robots.txt b/public/robots.txt
new file mode 100644
index 0000000000..37b576a4a0
--- /dev/null
+++ b/public/robots.txt
@@ -0,0 +1 @@
+# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb
new file mode 100644
index 0000000000..d19212abd5
--- /dev/null
+++ b/test/application_system_test_case.rb
@@ -0,0 +1,5 @@
+require "test_helper"
+
+class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
+ driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
+end
diff --git a/test/controllers/.keep b/test/controllers/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test/controllers/categories_controller_test.rb b/test/controllers/categories_controller_test.rb
new file mode 100644
index 0000000000..77c0ebc8e9
--- /dev/null
+++ b/test/controllers/categories_controller_test.rb
@@ -0,0 +1,88 @@
+require "test_helper"
+
+describe CategoriesController do
+
+ #everyone can view all categories
+ describe "index" do
+ it "returns a success status when there are categories" do
+ Category.count.must_be :>, 0, "No categories in the test fixtures"
+ get categories_path
+ must_respond_with :success
+ end
+
+ it "returns a success status when there are no categories" do
+ Category.destroy_all
+ get categories_path
+ must_respond_with :success
+ end
+ end
+
+ describe "show" do
+ it "returns a success status if given a valid category id" do
+ cat = categories(:book)
+ get category_path(cat.id)
+ must_respond_with :success
+ end
+
+ it "returns a not_found status if given an invalid category id" do
+ invalid_cat_id = Category.last.id + 1
+ get category_path(invalid_cat_id)
+ must_respond_with :not_found
+ end
+ end
+
+ describe "not logged in user" do
+ describe "new" do
+ it "returns a flash[:status] of failure, and redirects to products path" do
+ get new_category_path
+ flash[:status].must_equal :failure
+ must_respond_with :redirect
+ must_redirect_to products_path
+ end
+ end
+
+ describe "create" do
+ it "returns a flash[:status] of failure, and redirects to products path" do
+ new_cat = {
+ category: {
+ name: "new cat"
+ }
+ }
+
+ post categories_path, params: new_cat
+ flash[:status].must_equal :failure
+ must_respond_with :redirect
+ must_redirect_to products_path
+ end
+ end
+ end
+
+
+ describe "merchant logged in" do
+
+ before do
+ merchant = Merchant.first
+ login(merchant)
+ end
+
+ describe "new" do
+ it "returns a success status" do
+ get new_category_path
+ must_respond_with :success
+ end
+ end
+
+ describe "create" do
+ it "creates a new category with valid data and redirects to products_path" do
+ new_cat = {
+ category: {
+ name: "new cat"
+ }
+ }
+ post categories_path, params: new_cat
+ must_respond_with :redirect
+ must_redirect_to products_path
+ end
+ end
+ end
+end
diff --git a/test/controllers/merchants_controller_test.rb b/test/controllers/merchants_controller_test.rb
new file mode 100644
index 0000000000..85b3aa5902
--- /dev/null
+++ b/test/controllers/merchants_controller_test.rb
@@ -0,0 +1,183 @@
+require "test_helper"
+
+describe MerchantsController do
+ describe "for logged in merchant" do
+ before do
+ @merchant = merchants(:anders)
+ login(@merchant)
+ end
+
+ describe "index" do
+ it "succeeds when there are merchants" do
+ Merchant.count.must_be :>, 0, "No merchants in the test fixtures"
+ get merchants_path
+ must_respond_with :success
+ end
+
+ it "succeeds when there are no merchants" do
+ Merchant.destroy_all
+ get merchants_path
+ must_respond_with :success
+ end
+ end
+
+ describe "show" do
+ it "succeeds for a logged in merchant's own page" do
+ get merchant_path(@merchant)
+ must_respond_with :success
+ end
+
+ it "renders 404 not_found for a invalid merchant ID" do
+ invalid_merchant_id = Merchant.last.id + 1
+ get merchant_path(invalid_merchant_id)
+ must_respond_with :not_found
+ end
+
+ it "returns a success status for a different merchant's page" do
+ merchant = merchants(:bennett)
+ get merchant_path(merchant)
+ must_respond_with :success
+ end
+
+ # not sure how to test filters - since it is entirely a view thing?
+ it "returns a success status when parameters are passed in - for filtering orders" do
+ merchant = merchants(:bennett)
+ get merchant_path(merchant, status: "complete")
+ must_respond_with :success
+ end
+ end
+
+ describe "destroy" do
+ it "succeeds for a logged in merchant who is deleting their own account" do
+ delete merchant_path(@merchant.id)
+ must_redirect_to merchants_path
+
+ # The work should really be gone
+ Merchant.find_by(id: @merchant.id).must_be_nil
+ end
+
+ it "renders 404 not_found and does not update the DB for a bogus work ID" do
+ start_count = Merchant.count
+
+ bogus_work_id = Merchant.last.id + 1
+ delete merchant_path(bogus_work_id)
+ must_respond_with :not_found
+
+ Merchant.count.must_equal start_count
+ end
+
+ it "sets flash[:status] to failiure and redirects to root_path if a logged in merchant is trying to delete another merchant's account" do
+ other_merchant = merchants(:bennett)
+
+ delete merchant_path(other_merchant.id)
+ flash[:status].must_equal :failure
+ must_redirect_to root_path
+ end
+ end
+ end
+
+ describe "non logged in user" do
+ describe "index" do
+ it "returns success for a non-logged in user" do
+ get merchants_path
+ must_respond_with :success
+ end
+ end
+
+ describe "show" do
+ it "returns success for a non-logged in user" do
+ get merchant_path(merchants(:anders))
+ must_respond_with :success
+ end
+ end
+
+ describe "destroy" do
+ it "destroy fails for a non-logged in user" do
+ merchant = merchants(:bennett)
+ delete merchant_path(merchant.id)
+ must_redirect_to products_path
+ flash[:status].must_equal :failure
+ end
+ end
+ end
+
+ describe "create and login with auth_callback" do
+ it "logs in an existing user and redirects to the products route" do
+ # Count the merchants, to make sure we're not (for example) creating
+ # a new merchant every time we get a login request
+ start_count = Merchant.count
+
+ # Get a merchant from the fixtures
+ merchant = merchants(:anders)
+
+ # Tell OmniAuth to use this merchant's info when it sees
+ # an auth callback from github
+ login(merchant)
+ # OmniAuth.config.mock_auth[:github] = OmniAuth::AuthHash.new(mock_auth_hash(merchant))
+
+ # Send a login request for that merchant
+ # Note that we're using the named path for the callback, as defined
+ # in the `as:` clause in `config/routes.rb`
+ # get auth_callback_path(:github)
+
+ must_redirect_to products_path
+
+ # Since we can read the session, check that the user ID was set as expected
+ session[:merchant_id].must_equal merchant.id
+
+ # Should *not* have created a new user
+ Merchant.count.must_equal start_count
+ end
+
+ it "creates an account for a new merchant and redirects to the products route" do
+ start_count = Merchant.count
+
+ merchant = Merchant.new(provider: "github", uid: 123124564, username: "test_merchant", email: "test@merchant.com", name: "trio")
+
+ login(merchant)
+
+ must_redirect_to products_path
+ flash[:status].must_equal :success
+
+ # Should have created a new user
+ Merchant.count.must_equal start_count + 1
+
+ # The new user's ID should be set in the session
+ merchant_id = Merchant.find_by(username: merchant[:username]).id
+ session[:merchant_id].must_equal merchant_id
+ end
+
+ it "redirects to the products route if given invalid user data" do
+ invalid_merchant = Merchant.first
+ invalid_merchant.uid = ""
+
+ login(invalid_merchant)
+
+ must_redirect_to products_path
+ flash[:status].must_equal :failure
+ end
+
+ it "tells you you're already logged in if you're logged in." do
+ #log in again
+ merchant = merchants(:anders)
+ login(merchant)
+ login(merchant)
+
+ flash[:status].must_equal :failure
+ flash[:message].must_equal "You're already logged in, Bae!"
+ end
+
+ end
+
+ describe "logout" do
+ it "succeeds, redirects to products_path, sets flash[:status] to success and session[:merchant_id], [:cart] to nil" do
+ get logout_path
+ must_respond_with :redirect
+ must_redirect_to products_path
+ flash[:status].must_equal :success
+ session[:merchant_id].must_equal nil
+ session[:cart].must_equal nil
+ end
+ end
+
+end
diff --git a/test/controllers/order_products_controller_test.rb b/test/controllers/order_products_controller_test.rb
new file mode 100644
index 0000000000..4669fab568
--- /dev/null
+++ b/test/controllers/order_products_controller_test.rb
@@ -0,0 +1,190 @@
+require "test_helper"
+
+describe OrderProductsController do
+
+ before do
+ @product_params = {
+ product_id: products(:tricycle).id,
+ quantity: 1
+ }
+ end
+
+ describe "update_status" do
+ it "if entire order is complete, sets flash[:status] to success when order is saved with specific message, redirects merchant show page, and sets the orderproduct status and orders status to complete" do
+ #arrange
+ order_prod = order_products(:four)
+
+ #assert
+ patch update_status_path(order_prod.id)
+
+ #act
+ order_prod.reload
+ flash[:status].must_equal :success
+ order_prod.status.must_equal "complete"
+ order_prod.order.status.must_equal"complete"
+ flash[:message].must_equal "Order has been completed and shipped to buyer"
+ end
+
+ it "if order status is not complete, it was set flash[:status] to success and message to 'order has been completed and shipped to buyer', and the order status will not be complete" do
+ #arrange
+ order_prod = order_products(:two)
+
+ #assert
+ patch update_status_path(order_prod.id)
+
+ #act
+ order_prod.reload
+ flash[:status].must_equal :success
+ order_prod.status.must_equal "complete"
+ order_prod.order.status.must_equal "pending"
+ flash[:message].must_equal "Product has been added to order, Order is waiting on other products before shipping."
+ end
+ end
+
+ describe "destroy" do
+ it "deletes the orderproduct and redirects to order_path if there are still other orderproducts in the cart" do
+ order_prod = order_products(:two)
+ order_products(:three)
+ order = orders(:order4)
+
+ order = order_prod.order
+
+ delete order_product_path(order_prod.id)
+
+ must_respond_with :redirect
+ must_redirect_to order_path(order)
+ end
+
+ it "deletes the orderproduct and redirects to order_empty_cart_path if no more orderproducts in the order" do
+ order_prod = order_products(:four)
+ order_prod.order.id
+
+ delete order_product_path(order_prod.id)
+
+ must_respond_with :redirect
+ must_redirect_to order_empty_cart_path(:cart)
+ end
+ end
+
+ describe "create" do
+
+ it "creates an OrderProduct with a product and an order, creates a new order if no session[:cart] exists" do
+ orders_start = Order.count
+ start_count = OrderProduct.count
+
+ post create_order_product_path, params: @product_params
+ must_redirect_to order_path(session[:cart])
+
+ OrderProduct.count.must_equal start_count + 1
+ Order.count.must_equal orders_start + 1
+ end
+
+ it "creates a new OrderProduct with a product and an order if doesn't exist already, adds to existing cart if it has already been initiated" do
+ post create_order_product_path, params: @product_params
+ #I have to do this in order to set session.
+
+ orders_start = Order.count
+ start_count = OrderProduct.count
+
+
+ new_product = {
+ product_id: products(:tripod).id,
+ quantity: 1
+ }
+
+ post create_order_product_path, params: new_product
+ must_redirect_to order_path(session[:cart])
+
+ OrderProduct.count.must_equal start_count + 1
+ Order.count.must_equal orders_start
+ end
+
+ it "if an OrderProduct with the same product already exists, it will not create a new OrderProduct object" do
+ post create_order_product_path, params: @product_params
+
+ orders_start = Order.count
+ start_count = OrderProduct.count
+
+ post create_order_product_path, params: @product_params
+ must_redirect_to order_path(session[:cart])
+
+ OrderProduct.count.must_equal start_count
+ Order.count.must_equal orders_start
+ end
+
+ it "changes the quantity of an existing OrderProduct if trying to add more of the same product" do
+ post create_order_product_path, params: @product_params
+
+ op = OrderProduct.find_by(order_id: session[:cart])
+ quantity_start = op.quantity
+
+ # binding.pry
+ post create_order_product_path, params: @product_params
+
+ op.reload
+ op.quantity.must_equal quantity_start + 1
+ end
+
+ it "wont create if input is invalid" do
+ bad_product_params = {
+ product_id: products(:tricycle).id,
+ quantity: 0
+ }
+ start_count = OrderProduct.count
+
+ post create_order_product_path, params: bad_product_params
+ must_respond_with :bad_request
+ flash[:message].must_equal "Could not update cart."
+
+ OrderProduct.count.must_equal start_count
+ end
+
+ it "wont create if quantity is larger than inventory" do
+ bad_product_params = {
+ product_id: products(:tricycle).id,
+ quantity: (products(:tricycle).inventory + 1)
+ }
+ start_count = OrderProduct.count
+
+ post create_order_product_path, params: bad_product_params
+ must_respond_with :bad_request
+ flash[:message].must_equal "Not enough tricycles in stock, please revise the quantity selected."
+
+ OrderProduct.count.must_equal start_count
+ end
+ end
+
+ describe "update" do
+ it "changes the quantity of an existing OrderProduct, if enough inventory" do
+ post create_order_product_path, params: @product_params
+ order_prod = OrderProduct.last
+
+ update_order_prod = {
+ product_id: order_prod.product_id,
+ quantity: 2
+ }
+ patch order_product_path(order_prod.id), params: update_order_prod
+
+ must_respond_with :redirect
+ must_redirect_to order_path(order_prod.order)
+ flash[:status].must_equal :success
+
+ order_prod.reload
+ order_prod.quantity.must_equal 2
+ end
+
+ it "sets flash[:status] to failure if there isn't enough inventory to update" do
+ post create_order_product_path, params: @product_params
+ order_prod = OrderProduct.last
+
+ update_order_prod = {
+ product_id: order_prod.product_id,
+ quantity: 10
+ }
+ patch order_product_path(order_prod.id), params: update_order_prod
+
+ must_respond_with :bad_request
+ flash[:status].must_equal :failure
+ end
+ end
+end
diff --git a/test/controllers/orders_controller_test.rb b/test/controllers/orders_controller_test.rb
new file mode 100644
index 0000000000..c83c5d7140
--- /dev/null
+++ b/test/controllers/orders_controller_test.rb
@@ -0,0 +1,175 @@
+require "test_helper"
+
+describe OrdersController do
+ let :order_data {
+ order_data = {
+ order: {
+ status: "pending",
+ payment_info: payment_infos(:payment1)
+ }
+ }
+ }
+ let :order_id { Order.last.id }
+
+
+ describe "index" do
+ it "returns a success status for all orders" do
+ get orders_path
+ must_respond_with :success
+ end
+
+ it "returns a success status for no orders" do
+ Order.destroy_all
+ get orders_path
+ must_respond_with :success
+ end
+ end
+
+ describe "show" do
+ it "returns success when given the current cart id." do
+ product_params = {
+ product_id: products(:tricycle).id,
+ quantity: 1
+ }
+ post create_order_product_path, params: product_params
+
+ get order_path(session[:cart])
+ must_respond_with :success
+ end
+ it "returns not_found when given an invaild id" do
+ get order_path(order_id + 1)
+ must_respond_with :not_found
+ end
+ it "wont show past orders" do
+ get order_path(order_id)
+ must_redirect_to root_path
+ end
+ end
+
+ describe "update" do
+ it "returns not_found when given an invaild id" do
+ put order_path(order_id + 1), params: order_data
+ must_respond_with :not_found
+ end
+
+# NEED TO FIX ##############
+ it "returns success if the order exists and the change is valid" do
+ payment_data = {
+ payment_info: {
+ email: "example@example.com",
+ buyer_name: "name",
+ cvv: "123",
+ card_number: "123456",
+ zipcode: "12345",
+ mailing_address: "12 34th st",
+ expiration: "12/34"
+ }
+
+ }
+
+ orders(:order1).must_be :valid?
+ get checkout_path(orders(:order1))
+ put order_path(orders(:order1)), params: payment_data
+ session[:cart].must_be_nil
+ must_respond_with :redirect
+ must_redirect_to order_receipt_path(orders(:order1))
+ end
+ end
+
+ describe "checkout" do
+ it "sends the user to the checkout form" do
+ get checkout_path(order_id)
+ must_respond_with :success
+ end
+ it "not valid when order doesn't exist" do
+ get checkout_path(order_id + 1)
+ must_respond_with :not_found
+ end
+ end
+
+ describe "receipt" do
+ it "shows the receipt after a successful update/checkout" do
+ merchant = merchants(:anders)
+ login(merchant)
+ payment_data = {
+ payment_info: {
+ email: "example@example.com",
+ buyer_name: "name",
+ cvv: "123",
+ card_number: "123456",
+ zipcode: "12345",
+ mailing_address: "12 34th st",
+ expiration: "12/34"
+ }
+
+ }
+ patch order_path(orders(:order1)), params: payment_data
+
+ get order_receipt_path(orders(:order1))
+ must_respond_with :success
+ end
+
+ it "cannot see a receipt twice; receipts will only show immediately after a purchase" do
+
+ payment_data = {
+ payment_info: {
+ email: "example@example.com",
+ buyer_name: "name",
+ cvv: "123",
+ card_number: "123456",
+ zipcode: "12345",
+ mailing_address: "12 34th st",
+ expiration: "12/34"
+ }
+ }
+ patch order_path(orders(:order1)), params: payment_data
+
+ get order_receipt_path(orders(:order1))
+ must_respond_with :success
+
+ get order_receipt_path(orders(:order1))
+ must_respond_with :redirect
+ flash[:status].must_equal :failure
+ end
+
+ it "shows the receipt to the merchant who is the owner of the orderproduct; so a merchant can see a receipt twice" do
+ merchant = merchants(:anders)
+ login(merchant)
+
+ payment_data = {
+ payment_info: {
+ email: "example@example.com",
+ buyer_name: "name",
+ cvv: "123",
+ card_number: "123456",
+ zipcode: "12345",
+ mailing_address: "12 34th st",
+ expiration: "12/34"
+ }
+ }
+ patch order_path(orders(:order1)), params: payment_data
+
+ get order_receipt_path(orders(:order1))
+ must_respond_with :success
+
+ get order_receipt_path(orders(:order1))
+ must_respond_with :success
+ end
+ end
+
+ describe "destroy" do
+ it "returns success if the order was destroyed" do
+ total = Order.count
+ delete order_path(orders(:order1))
+ must_respond_with :redirect
+ must_redirect_to root_path
+ total.must_equal Order.count + 1
+ end
+
+ it "returns not_found when given an invaild id" do
+ put order_path(order_id + 1)
+ must_respond_with :not_found
+ end
+
+ end
+end
diff --git a/test/controllers/products_controller_test.rb b/test/controllers/products_controller_test.rb
new file mode 100644
index 0000000000..e56d1aa19b
--- /dev/null
+++ b/test/controllers/products_controller_test.rb
@@ -0,0 +1,241 @@
+require "test_helper"
+
+describe ProductsController do
+
+##########LOGGED IN MERCHANT#################
+ describe "logged in merchant" do
+ before do
+ merchant = Merchant.first
+ login(merchant)
+ end
+
+ describe "root" do
+ it "returns a success status" do
+ get root_path
+ must_respond_with :success
+ end
+ end
+
+ describe "index" do
+ it "shows all products" do
+ get products_path
+ must_respond_with :success
+ end
+
+ it "returns success status when there are no products" do
+ Product.destroy_all
+ get products_path
+ must_respond_with :success
+ end
+ end
+
+ describe "show" do
+ it "returns success when given a valid product id" do
+ product_id = Product.first.id
+ # user_id = session[:user_id]
+ get product_path(product_id)
+ must_respond_with :success
+ end
+
+ it "returns not_found when given a bad work id" do
+ bad_product_id = Product.last.id + 1
+ get product_path(bad_product_id)
+ must_respond_with :not_found
+ end
+ end
+
+ describe "new" do
+ it "creates a new product successfully" do
+ get new_product_path
+ must_respond_with :success
+ end
+ end
+
+ describe "create" do
+ it "saves and redirects to products_path when the product data is valid" do
+ product_data = {
+ product: {
+ name: "book",
+ price: 4.32,
+ inventory: 2,
+ category_ids: [categories(:book).id]
+ }
+ }
+ product = Product.new(product_data[:product])
+ product.merchant_id = session[:merchant_id]
+ product.must_be :valid?
+ start_product_count = Product.count
+
+ post products_path, params: product_data
+ must_respond_with :redirect
+ must_redirect_to products_path(product.id)
+ Product.count.must_equal start_product_count + 1
+ end
+
+ it "renders a bad_request when the product data is invalid" do
+ bad_product = {
+ product: {
+ name: "book",
+ # no price given!!
+ }
+ }
+ Product.new(bad_product[:product]).wont_be :valid?
+ start_product_count = Product.count
+ post products_path, params: bad_product
+
+ must_respond_with :bad_request
+ Product.count.must_equal start_product_count
+ end
+ end
+
+ describe "edit" do
+ it "returns success when given a valid product id" do
+ product_id = Product.first.id
+ get product_path(product_id)
+ must_respond_with :success
+ end
+
+ it "returns not_found when given a bad work id" do
+ bad_product_id = Product.last.id + 1
+ get product_path(bad_product_id)
+ must_respond_with :not_found
+ end
+ end
+
+ describe "update" do
+ it "returns success when change is valid" do
+ product = Product.first
+ product_data = {
+ product: {
+ name: "book",
+ price: 4.32,
+ category_ids: Category.first.id
+ }
+ }
+ product.update_attributes(product_data[:product])
+ product.must_be :valid?
+
+ patch product_path(product), params: product_data
+ must_respond_with :redirect
+ must_redirect_to product_path(product)
+
+ product.reload
+ product.name.must_equal product_data[:product][:name]
+ end
+
+ it "returns not_found if product id is invalid" do
+ bad_product_id = Product.last.id + 1
+ product_data = {
+ product: {
+ name: " title"
+ }
+ }
+ patch product_path(bad_product_id), params: product_data
+ must_respond_with :not_found
+ end
+
+ it "returns bad_request when change is invalid" do
+ product = Product.first
+ bad_product_data = {
+ product: {
+ name: ""
+ }
+ }
+ product.update_attributes(bad_product_data[:product])
+ product.wont_be :valid?
+ start_product_count = Product.count
+
+ patch product_path(product), params: bad_product_data
+ must_respond_with :bad_request
+ Product.count.must_equal start_product_count
+ end
+ end
+
+ describe "destroy" do
+ it "returns success when product is deleted" do
+ product_count = Product.count
+ product_id = Product.first
+ delete product_path(product_id)
+ must_respond_with :redirect
+ must_redirect_to products_path
+ Product.count.must_equal product_count - 1
+ end
+
+ it "returns not_found if given invalid product id" do
+ bad_product_id = Product.last.id + 1
+
+ delete product_path(bad_product_id)
+ must_respond_with :not_found
+ end
+ end
+ end
+
+##########NOT LOGGED IN USERS#################
+ describe "not logged in users" do
+ describe "root" do
+ it "returns a success status" do
+ get root_path
+ must_respond_with :success
+ end
+ end
+
+ describe "index" do
+ it "shows all products" do
+ get products_path
+ must_respond_with :success
+ end
+
+ it "returns success status when there are no products" do
+ Product.destroy_all
+ get products_path
+ must_respond_with :success
+ end
+ end
+
+ describe "show" do
+ it "returns success when given a valid product id" do
+ product_id = Product.first.id
+ # user_id = session[:user_id]
+ get product_path(product_id)
+ must_respond_with :success
+ end
+
+ it "returns not_found when given a bad work id" do
+ bad_product_id = Product.last.id + 1
+ get product_path(bad_product_id)
+ must_respond_with :not_found
+ end
+ end
+
+ describe "new" do
+ it "will set flash[:status] to failure and redirect to products_path" do
+ get new_product_path
+ flash[:status].must_equal :failure
+ must_respond_with :redirect
+ must_redirect_to products_path
+ end
+ end
+
+ describe "edit" do
+ it "will set flash[:status] to failure and redirect to products_path" do
+ product_id = Product.first.id
+ get edit_product_path(product_id)
+ flash[:status].must_equal :failure
+ flash[:message].must_equal "You must be logged in to do that!"
+ must_respond_with :redirect
+ must_redirect_to products_path
+ end
+ end
+
+ describe "destroy" do
+ it "will set flash[:status] to failure and redirect to products_path" do
+ delete product_path(Product.first)
+ flash[:status].must_equal :failure
+ must_respond_with :redirect
+ must_redirect_to products_path
+ end
+ end
+
+ #Do we need tests for #create and #update here?
+ end
+end
diff --git a/test/controllers/reviews_controller_test.rb b/test/controllers/reviews_controller_test.rb
new file mode 100644
index 0000000000..5c78d30571
--- /dev/null
+++ b/test/controllers/reviews_controller_test.rb
@@ -0,0 +1,136 @@
+require "test_helper"
+
+describe ReviewsController do
+ # let (:review) {reviews(:review1)}
+
+ #######LOGGED IN MERCHANT##########
+ describe "logged in merchant" do
+ before do
+ merchant = merchants(:anders)
+ login(merchant)
+ end
+
+ describe "new" do
+ it "merchants can go to a new review path for other products" do
+ product = products(:tripod)
+ get new_product_review_path(product)
+ must_respond_with :success
+ end
+
+ it "doesn't allow a merchant to go to a new review on their own product" do
+
+ product = products(:tricycle)
+ start_review_count = Review.count
+ get new_product_review_path(product)
+
+ must_redirect_to products_path
+ flash[:message].must_equal "You cannot review your own product!"
+ Review.count.must_equal start_review_count
+ end
+ end
+
+ describe "create" do
+ it "just in case, doesn't allow a merchant create a review on their own product" do
+ # TODO: come back to this test
+ # review_data = {
+ # review: {
+ # rating: 3,
+ # text: "I loved it!",
+ # product_id: product.id
+ # }
+ # }
+ # product = products(:tricycle)
+ # start_review_count = Review.count
+ # post reviews_path, params: review_data
+ #
+ # must_redirect_to products_path
+ # flash[:message].must_equal "You cannot review your own product!"
+ # Review.count.must_equal start_review_count
+ end
+
+ it "does allow a merchant to review other products" do
+ product = products(:tripod)
+ review_data = {
+ review: {
+ rating: 3,
+ text: "I loved it!",
+ product_id: product.id
+ }
+ }
+ puts review_data[:review][:product_id]
+ product.reviews.new(review_data[:review]).must_be :valid?
+ start_review_count = Review.count
+
+ post reviews_path, params: review_data
+
+ must_respond_with :redirect
+ must_redirect_to product_path(product.id)
+ Review.count.must_equal start_review_count + 1
+
+ end
+
+ end
+ end
+
+ #######NOT LOGGED IN USER##########
+ describe "not logged in user" do
+
+ describe "new" do
+ it "responds with success when directed to the new review path" do
+ product = Product.first.id
+ get new_product_review_path(product)
+ must_respond_with :success
+ end
+
+ it "returns not_found if given invalid product id" do
+ invalid_prod_id = Product.last.id + 1
+ get new_product_review_path(invalid_prod_id)
+ must_respond_with :not_found
+ end
+ end
+
+ describe "create" do
+ it "saves and redirects to product show page when the review data is valid" do
+
+ product = Product.first
+ review_data = {
+ review: {
+ rating: 3,
+ text: "I loved it!",
+ product_id: product.id
+ }
+ }
+ puts review_data[:review][:product_id]
+ product.reviews.new(review_data[:review]).must_be :valid?
+ start_review_count = Review.count
+
+ post reviews_path, params: review_data
+
+ must_respond_with :redirect
+ must_redirect_to product_path(product.id)
+ Review.count.must_equal start_review_count + 1
+ end
+
+ it "sends :bad_request if data is invalid" do
+
+ product = Product.first
+ review_data = {
+ review: {
+ rating: 0,
+ text: "I loved it!",
+ product_id: product.id
+ }
+ }
+ puts review_data[:review][:product_id]
+ product.reviews.new(review_data[:review]).wont_be :valid?
+ start_review_count = Review.count
+
+ post reviews_path, params: review_data
+ must_respond_with :bad_request
+
+ Review.count.must_equal start_review_count
+ end
+ end
+
+ end
+end
diff --git a/test/fixtures/.keep b/test/fixtures/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test/fixtures/categories.yml b/test/fixtures/categories.yml
new file mode 100644
index 0000000000..6678e967a8
--- /dev/null
+++ b/test/fixtures/categories.yml
@@ -0,0 +1,17 @@
+# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+# This model initially had no columns defined. If you add columns to the
+# model remove the "{}" from the fixture names and add the columns immediately
+# below each fixture, per the syntax in the comments below
+# #
+# one: {}
+# # column: value
+# #
+# two: {}
+# column: value
+
+book:
+ name: book
+
+movie:
+ name: movie
diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test/fixtures/merchants.yml b/test/fixtures/merchants.yml
new file mode 100644
index 0000000000..216b466a63
--- /dev/null
+++ b/test/fixtures/merchants.yml
@@ -0,0 +1,22 @@
+# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+anders:
+ provider: github
+ uid: 12345
+ username: anders
+ email: anders@tricycle.com
+ name: "Anders"
+
+lauren:
+ provider: github
+ uid: 67896789
+ username: lauren
+ email: lauren@tricycle.com
+ name: "Lauren"
+
+bennett:
+ provider: github
+ uid: 123123123
+ username: bennett
+ email: bennett@tricycle.com
+ name: "Bennett"
diff --git a/test/fixtures/order_products.yml b/test/fixtures/order_products.yml
new file mode 100644
index 0000000000..ff20d7310a
--- /dev/null
+++ b/test/fixtures/order_products.yml
@@ -0,0 +1,31 @@
+# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+one:
+ quantity: 1
+ product: tricycle
+ order: order5
+ status: "paid"
+
+two:
+ quantity: 1
+ product: tripod
+ order: order4
+ status: ""
+
+three:
+ quantity: 1
+ product: tricycle
+ order: order4
+ status: ""
+
+four:
+ quantity: 1
+ product: tricycle
+ order: order1
+ status: ""
+
+five:
+ quantity: 1
+ product: tripod
+ order: order3
+ status: ""
diff --git a/test/fixtures/orders.yml b/test/fixtures/orders.yml
new file mode 100644
index 0000000000..90b1328592
--- /dev/null
+++ b/test/fixtures/orders.yml
@@ -0,0 +1,19 @@
+# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+order1:
+ status: "pending"
+
+order2:
+ status: "pending"
+
+order3:
+ status: "complete"
+
+order4:
+ status: "pending"
+
+order5:
+ status: "paid"
+
+order6:
+ status: 'pending'
diff --git a/test/fixtures/payment_infos.yml b/test/fixtures/payment_infos.yml
new file mode 100644
index 0000000000..b69b7c6a42
--- /dev/null
+++ b/test/fixtures/payment_infos.yml
@@ -0,0 +1,24 @@
+# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+# This model initially had no columns defined. If you add columns to the
+# model remove the "{}" from the fixture names and add the columns immediately
+# below each fixture, per the syntax in the comments below
+#
+
+payment1:
+ email: "bennett@email.com"
+ mailing_address: "123 S 1st Ave"
+ buyer_name: "Bennett"
+ card_number: "1234 5678 9101 1121"
+ expiration: "01/12"
+ cvv: "123"
+ zipcode: "98013"
+
+payment2:
+ email: "suzy@email.com"
+ mailing_address: "456 N 2nd Ave"
+ buyer_name: "Suzy"
+ card_number: "3141 5161 7181 9202"
+ expiration: "03/07"
+ cvv: "678"
+ zipcode: "73452"
diff --git a/test/fixtures/products.yml b/test/fixtures/products.yml
new file mode 100644
index 0000000000..1dd77c709d
--- /dev/null
+++ b/test/fixtures/products.yml
@@ -0,0 +1,29 @@
+# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+# This model initially had no columns defined. If you add columns to the
+# model remove the "{}" from the fixture names and add the columns immediately
+# below each fixture, per the syntax in the comments below
+#
+# one: {}
+# # column: value
+# #
+# two: {}
+# column: value
+
+
+tricycle:
+ name: tricycle
+ description: "A fun toy!"
+ merchant: anders
+ inventory: 4
+ photo_url: https://i-d-images.vice.com/images/2016/09/16/bill-murray-has-a-couple-of-shifts-at-a-brooklyn-bar-this-weekend-body-image-1473999364.jpg
+ price: 2.40
+ # category_ids
+
+tripod:
+ name: tripod
+ description: "Good for cameras"
+ merchant: lauren
+ inventory: 4
+ photo_url: https://i-d-images.vice.com/images/2016/09/16/bill-murray-has-a-couple-of-shifts-at-a-brooklyn-bar-this-weekend-body-image-1473999364.jpg
+ price: 12.56
diff --git a/test/fixtures/reviews.yml b/test/fixtures/reviews.yml
new file mode 100644
index 0000000000..dc3b5cd7f2
--- /dev/null
+++ b/test/fixtures/reviews.yml
@@ -0,0 +1,26 @@
+# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+# This model initially had no columns defined. If you add columns to the
+# model remove the "{}" from the fixture names and add the columns immediately
+# below each fixture, per the syntax in the comments below
+#
+# one: {}
+# # column: value
+# #
+# two: {}
+# column: value
+
+review1:
+ rating: 1
+ text: "Terrible"
+ product: tricycle
+
+review2:
+ rating: 4
+ text: "Great"
+ product: tricycle
+
+review3:
+ rating: 5
+ text: "A hit!"
+ product: tripod
diff --git a/test/helpers/.keep b/test/helpers/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test/integration/.keep b/test/integration/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test/mailers/.keep b/test/mailers/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test/models/.keep b/test/models/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test/models/category_test.rb b/test/models/category_test.rb
new file mode 100644
index 0000000000..96a9dc36dc
--- /dev/null
+++ b/test/models/category_test.rb
@@ -0,0 +1,73 @@
+require "test_helper"
+
+describe Category do
+
+ let (:category) {categories(:book)}
+
+ describe "relations" do
+ it "must be connected to products" do
+ category.must_respond_to :products
+ end
+ end
+
+ describe "validations" do
+ it "is valid when given valid category data" do
+ new_cat = Category.new(name: "record")
+ new_cat.must_be :valid?
+ end
+
+ it "requires a name" do
+ invalid_cat = Category.new(name: "")
+ invalid_cat.wont_be :valid?
+ end
+
+ it "requres a name that is unique" do
+ new_cat = Category.new(name: "record")
+ new_cat.save
+ new_cat_2 = Category.new(name: "record")
+ new_cat_2.wont_be :valid?
+ end
+ end
+
+ describe "#self.spot" do
+ it "can be called" do
+ Category.must_respond_to :spot
+ end
+
+ it "returns a Product object" do
+ Category.spot.must_be_instance_of Product
+ end
+
+ it "returns nil if no products" do
+ Product.destroy_all
+ Category.spot.must_equal nil
+ end
+ end
+
+ describe "#self.root_page_seasonal_pick" do
+ it "can be called" do
+ Category.must_respond_to :root_page_seasonal_pick
+ end
+
+ it "returns an array of Product objects" do
+ halloween_category = Category.create!(name: "halloween")
+ product = products(:tricycle)
+ product.categories << halloween_category
+
+ array_products = Category.root_page_seasonal_pick
+ array_products.must_be_instance_of Array
+ array_products[0].must_be_instance_of Product
+ end
+
+ it "returns an empty array of if no products" do
+ Product.destroy_all
+ Category.root_page_seasonal_pick.must_be :empty?
+ end
+
+ it "returns an empty array if no categories" do
+ Category.destroy_all
+ Category.root_page_seasonal_pick.must_be :empty?
+ end
+ end
+
+end
diff --git a/test/models/merchant_test.rb b/test/models/merchant_test.rb
new file mode 100644
index 0000000000..3030334fc4
--- /dev/null
+++ b/test/models/merchant_test.rb
@@ -0,0 +1,135 @@
+require "test_helper"
+
+describe Merchant do
+ before do
+ @m = Merchant.new
+ @valid_test_m = Merchant.new(username: "tricycle", email: "tricycle@tricycle.com" )
+ end
+
+ describe "relations" do
+ it "responds to products" do
+ @m.must_respond_to :products
+ end
+
+ it "has one or many products" do
+ @m.must_respond_to :products
+ @m.products.must_be :empty?
+
+ product = products(:tricycle)
+
+ @m.products << product
+
+ @m.products.must_include product
+ end
+ end
+
+ describe "validations" do
+ it "is valid when given valid merchant data" do
+ @valid_test_m.must_be :valid?
+ end
+
+ it "requires a username" do
+ merchant = Merchant.new(username: "", email: "email@email.com")
+ merchant.valid?.must_equal false
+ merchant.errors.messages.must_include :username
+ end
+
+ it "requires a unique username" do
+ merchant = merchants(:anders)
+ same_username = Merchant.new(username: merchant.username, email: merchant.username)
+ same_username.valid?.must_equal false
+ same_username.errors.messages.must_include :username
+ end
+
+ it "requires an email" do
+ merchant = Merchant.new(username: "username", email: "")
+ merchant.valid?.must_equal false
+ merchant.errors.messages.must_include :email
+ end
+
+ it "requires a unique email" do
+ merchant = merchants(:anders)
+ same_email = Merchant.new(username: merchant.username, email: merchant.username)
+ same_email.valid?.must_equal false
+ same_email.errors.messages.must_include :email
+ end
+
+ it "requires an email in a certain format" do
+ merchant = Merchant.new(username: "username", email: "tricycle")
+ merchant.valid?.must_equal false
+ merchant.errors.messages.must_include :email
+
+ merchant1 = Merchant.new(username: "username", email: "tricycle@")
+ merchant1.valid?.must_equal false
+ merchant.errors.messages.must_include :email
+
+ merchant2 = Merchant.new(username: "username", email: "tricycle@tricycle")
+ merchant2.valid?.must_equal false
+ merchant.errors.messages.must_include :email
+
+ merchant3 = Merchant.new(username: "username", email: "tricycle@tricycle.")
+ merchant3.valid?.must_equal false
+ merchant.errors.messages.must_include :email
+ end
+ end
+
+ describe "custom methods" do
+
+ #below test not passing - in merchant.rb, if I comment out all the auth_hash['info'] lines, then it passes. In test_helper.rb, #mock_auth_hash does not set an ['info']['name']... but that can't be all the problem (if it is even a problem), because ['info']['email'] and ['info']['nickname'] also aren't being recognized
+ describe "#self.from_auth_hash" do
+ it "returns an instance of Merchant" do
+ merchant = merchants(:lauren)
+
+ merchant_instance = Merchant.from_auth_hash('github', mock_auth_hash(merchant))
+
+ merchant_instance.must_be_instance_of Merchant
+ end
+ end
+
+ describe "relevant_orders" do
+ it "returns an Array of Hashes Order objects" do
+ merchant = merchants(:lauren)
+ should_return = merchant.relevant_orders
+ should_return.must_be_instance_of Array
+ should_return[0].must_be_instance_of Hash
+ end
+
+ it "returns an empty Array if no orders" do
+ Order.destroy_all
+ merchant = merchants(:lauren)
+ should_return = merchant.relevant_orders
+ should_return.length.must_equal 0
+ end
+ end
+
+ describe "sort_orders_by_status" do
+ it "returns the order hashes like relevant_orders, but only for a certain status" do
+ merchant = merchants(:lauren)
+ merchant.sort_orders_by_status('paid').each do |order|
+ order[:order].status.must_equal "paid"
+ end
+ end
+ # the no orders edge case is tested above in relevant_orders
+ end
+
+ describe "total_revenue" do
+ it "counts the completed orders total money" do
+ merchant = merchants(:lauren)
+ should_return = merchant.total_revenue('complete')
+ should_return.must_equal products(:tripod).price
+ end
+ it "does the same for paid (waiting to be completed) orders" do
+ merchant = merchants(:anders)
+ should_return = merchant.total_revenue('paid')
+ should_return.must_equal products(:tricycle).price
+ end
+
+ it "returns 0 if no orders for that status" do
+ merchant = merchants(:bennett)
+ merchant.total_revenue('paid').must_equal 0
+ end
+ end
+
+ end
+
+end
diff --git a/test/models/order_product_test.rb b/test/models/order_product_test.rb
new file mode 100644
index 0000000000..36372b594c
--- /dev/null
+++ b/test/models/order_product_test.rb
@@ -0,0 +1,42 @@
+require "test_helper"
+
+describe OrderProduct do
+ let (:op) { order_products(:five) }
+ let (:order) { orders(:order1) }
+ let (:product) { products(:tricycle)}
+
+ describe "relationships" do
+ it "has an order" do
+ op.must_respond_to :order
+ op.order.must_be_kind_of Order
+ end
+
+ it "has a product" do
+ op.must_respond_to :product
+ op.product.must_be_kind_of Product
+ end
+
+ it "has a merchant" do
+ op.must_respond_to :merchant
+ op.merchant.must_be_kind_of Merchant
+ end
+ end
+
+ describe "vaildations" do
+ it "works with a number greater than 0" do
+ [1, 3, 7, 10].each do |quantity|
+ op_valid = OrderProduct.new(order: order, product: product, quantity: quantity)
+ op_valid.valid?.must_equal true
+ end
+ end
+
+ it "doesn't work with non-valid things." do
+ [0, -7, "nil"].each do |quantity|
+ op_invalid = OrderProduct.new(order: order, product: product, quantity: quantity)
+ op_invalid.valid?.must_equal false
+ op_invalid.errors.messages.must_include :quantity
+ end
+
+ end
+ end
+end
diff --git a/test/models/order_test.rb b/test/models/order_test.rb
new file mode 100644
index 0000000000..59bd9a7804
--- /dev/null
+++ b/test/models/order_test.rb
@@ -0,0 +1,80 @@
+require "test_helper"
+
+describe Order do
+ let (:order) { orders(:order1) }
+ describe "relationships" do
+ it "has a list of order_products, which have products." do
+ order.must_respond_to :order_products
+ order.must_respond_to :products
+ order.order_products.each do |op|
+ op.product.must_be_kind_of Product
+ end
+ end
+
+ it "has one payment_info" do
+ order.must_respond_to :payment_info
+ end
+ end
+
+ describe "methods" do
+ describe "products" do
+ it "returns an array of products for that order" do
+ order.products.each do |product|
+ product.must_be_kind_of Product
+ end
+ end
+
+ it "returns an empty array if the order has no products" do
+ empty_order = Order.new
+ empty_order.products.must_be_empty
+ end
+ end
+ end
+
+ describe "order_complete?" do
+ it "can be called" do
+ order = orders(:order3)
+ order.must_respond_to :order_complete?
+ end
+ it "returns true if the all order product status is complete" do
+ op = order_products(:four)
+ order = orders(:order1)
+ op.status = "complete"
+ op.save
+
+ order.order_complete?.must_equal true
+ end
+
+ it "returns false if the order is not complete" do
+ order_products(:four)
+ order = orders(:order1)
+
+ order.order_complete?.must_equal false
+ end
+
+ #TODO: what if there are no orderproducts?
+ # it "sets flash[:status] to failure is there are no orderproducts" do
+ # OrderProducts.destroy_all
+ # order = orders(:order1)
+ #
+ # order.order_complete?.
+ # end
+
+ end
+
+ describe "order_total" do
+ it "returns the total of the whole order if no merchant is passed" do
+ orders(:order4).order_total.must_equal products(:tripod).price + products(:tricycle).price
+ end
+
+ it "returns the total of the products belonging to a merchant if one is passed" do
+ orders(:order4).order_total(merchant: merchants(:lauren)).must_equal products(:tripod).price
+ end
+
+ it "returns 0 when there are no products" do
+ orders(:order4).order_total(merchant: merchants(:bennett)).must_equal 0
+
+ orders(:order6).order_total.must_equal 0
+ end
+ end
+end
diff --git a/test/models/payment_info_test.rb b/test/models/payment_info_test.rb
new file mode 100644
index 0000000000..89c933926d
--- /dev/null
+++ b/test/models/payment_info_test.rb
@@ -0,0 +1,90 @@
+require "test_helper"
+
+describe PaymentInfo do
+ let (:payment_info) { payment_infos(:payment1) }
+ describe "relationships" do
+ it "has one order" do
+ payment_info.must_respond_to :order
+ end
+ end
+
+ describe "validations" do
+ before do
+ @invaild_payment = PaymentInfo.new(buyer_name: "", email: "")
+ end
+
+ it "is valid when given valid merchant data" do
+ payment_info.must_be :valid?
+ end
+
+ it "requires a buyer_name" do
+ @invaild_payment.valid?.must_equal false
+ @invaild_payment.errors.messages.must_include :buyer_name
+ end
+
+ it "requires an email" do
+ @invaild_payment.valid?.must_equal false
+ @invaild_payment.errors.messages.must_include :email
+ end
+
+ it "requires an email in a certain format" do
+ @invaild_payment.email = "tricycle"
+ @invaild_payment.valid?.must_equal false
+ @invaild_payment.errors.messages.must_include :email
+
+ @invaild_payment.email = "tricycle@"
+ @invaild_payment.valid?.must_equal false
+ @invaild_payment.errors.messages.must_include :email
+
+ @invaild_payment.email = "tricycle@tricycle"
+ @invaild_payment.valid?.must_equal false
+ @invaild_payment.errors.messages.must_include :email
+
+ @invaild_payment.email = "tricycle@tricycle."
+ @invaild_payment.valid?.must_equal false
+ @invaild_payment.errors.messages.must_include :email
+ end
+
+ it "requires a card_number" do
+ @invaild_payment.valid?.must_equal false
+ @invaild_payment.errors.messages.must_include :card_number
+ end
+
+ it "requires a card_number that is equal to or greater than 4 characters" do
+ payment_info.card_number = "12"
+ payment_info.wont_be :valid?
+ end
+
+ it "requires an expiration" do
+ @invaild_payment.valid?.must_equal false
+ @invaild_payment.errors.messages.must_include :expiration
+ end
+
+ it "requires an mailing_address" do
+ @invaild_payment.valid?.must_equal false
+ @invaild_payment.errors.messages.must_include :mailing_address
+ end
+
+ it "requires an cvv" do
+ @invaild_payment.valid?.must_equal false
+ @invaild_payment.errors.messages.must_include :cvv
+ end
+
+ it "requires an zipcode" do
+ @invaild_payment.valid?.must_equal false
+ @invaild_payment.errors.messages.must_include :zipcode
+ end
+ end
+
+ describe "#last_four_cc" do
+ it "can be called" do
+ payment_info.must_respond_to :last_four_cc
+ end
+
+ it "returns a string of the last four characters of card_number" do
+ payment_info.card_number = "12345"
+ payment_info.last_four_cc.must_equal "2345"
+ end
+ end
+
+end
diff --git a/test/models/product_test.rb b/test/models/product_test.rb
new file mode 100644
index 0000000000..da89d5b6a6
--- /dev/null
+++ b/test/models/product_test.rb
@@ -0,0 +1,200 @@
+require "test_helper"
+
+describe Product do
+
+ before do
+ @p = Product.new
+ end
+
+ describe "relations" do
+ it "must respond to merchant" do
+ @p.must_respond_to :merchant
+ end
+
+ it "has a merchant" do
+ prod = products(:tricycle)
+ merch = merchants(:anders)
+
+ prod.merchant.must_equal merch
+ prod.merchant_id.must_equal merch.id
+ end
+
+ it "can have order_products" do
+ @p.must_respond_to :order_products
+
+ prod = products(:tricycle)
+ order = orders(:order1)
+ order_prod = OrderProduct.create!(quantity: 1, product: prod, order: order)
+
+ prod.order_products << order_prod
+
+ prod.order_products.must_include order_prod
+ # prod = products(:tricycle)
+ # order_prod = order_products(:one)
+ #
+ # prod.order_products.must_equal order_prod
+ # prod.order_products_ids.must_equal order_prod.id
+ end
+
+ #TODO: tried to work on this test. not understanding the through relationship well enough. Product doesn't have a direct relationship with Order, so how to connect them in tests?
+ it "can have orders through order_products" do
+ @p.must_respond_to :orders
+ #
+ # prod = products(:tricycle)
+ # order = orders(:order2)
+ # order_prod = OrderProduct.create!(quantity: 1, product: prod, order: order)
+ #
+ # prod.order_products.product_id.must_equal order.order_products.product_id
+ end
+
+ it "can have reviews" do
+ @p.must_respond_to :reviews
+
+ product = products(:tricycle)
+
+ review = Review.create!(rating: 4, text: "great", product_id: product.id)
+ product.reviews << review
+ product.reviews.must_include review
+ end
+
+ it "has at least one category, and can have multiple" do
+ @p.must_respond_to :categories
+
+ @p.categories.must_be :empty?
+
+ cat = Category.create!(name: "computers")
+ @p.categories << cat
+ @p.categories.must_include cat
+
+ cat2 = Category.create!(name: "three-legged chairs")
+ @p.categories << cat2
+ @p.categories.must_include cat2
+ end
+
+ end
+
+ describe 'validations' do
+ it 'is valid' do
+ b = Product.new(name: "book", price: 2, merchant_id: Product.first.merchant_id, inventory: Product.first.inventory)
+ b.category_ids = Category.first.id
+ b.must_be :valid?
+ end
+
+ it 'requires a name' do
+ is_valid = @p.valid?
+ is_valid.must_equal false
+ @p.errors.messages.must_include :name
+ end
+
+ it 'requires a unique name' do
+ name = "test book"
+ Product.create!(name: name, price: 1, merchant_id: Product.first.merchant_id, inventory: Product.first.inventory, category_ids: Category.first.id)
+ b2 = Product.new(name: name, price: 2, merchant_id: Product.first.merchant_id, inventory: Product.first.inventory, category_ids: Category.first.id)
+ b2.wont_be :valid?
+ end
+
+ it 'requires a price' do
+ is_valid = @p.valid?
+ is_valid.must_equal false
+ @p.errors.messages.must_include :price
+ end
+
+ it 'requires a price greater than 0' do
+ b = Product.new(name: "tom petty video", price: -1)
+ is_valid = b.valid?
+ is_valid.must_equal false
+ b.errors.messages.must_include :price
+ end
+
+ it "requires inventory that is greater or equal to 0" do
+ p = Product.new(name: "tom petty video", price: 1)
+ is_valid = p.valid?
+ is_valid.must_equal false
+ p.errors.messages.must_include :inventory
+
+ p2 = Product.new(name: "tom petty video", price: 1, inventory: -1)
+ is_valid = p2.valid?
+ is_valid.must_equal false
+ p2.errors.messages.must_include :inventory
+ end
+
+ it "requires the presence of a category" do
+ p = Product.new(name: "tom petty video", price: 1, inventory: 1)
+ is_valid = p.valid?
+ is_valid.must_equal false
+ p.errors.messages.must_include :category_ids
+ end
+ end
+
+ #TODO:
+ describe "increase_inventory" do
+
+
+ end
+
+ describe "decrease_inventory" do
+ let(:tricycle) { products(:tricycle) }
+ it "decreases the inventory by the given quantity" do
+ start = tricycle.inventory
+
+ tricycle.decrease_inventory(1)
+
+ tricycle.inventory.must_equal start - 1
+ end
+ end
+
+ describe "check_inventory" do
+ let(:tripod) { products(:tripod) }
+ it "returns true when there is inventory, and returns false when there isn't" do
+ max = tripod.inventory
+
+ tripod.check_inventory(max).must_equal true
+
+ tripod.check_inventory(max - 1).must_equal true
+
+ tripod.check_inventory(max + 1).must_equal false
+ end
+
+ it "returns false if the inventory is 0" do
+ tripod.inventory = 0
+
+ tripod.check_inventory(1).must_equal false
+ end
+ #since quantity has been validated to be always more than 0, do I still need to check other edge cases?
+
+ end
+
+ describe "#average_rating" do
+ it "returns an Integer that is the average of all ratings" do
+ #arrange
+
+ product = Product.first
+
+ review = Review.create!(rating: 5, product_id: product.id)
+ review_2 = Review.create!(rating: 3, product_id: product.id)
+ review_3 = Review.create!(rating: 1, product_id: product.id)
+
+ all_reviews_product_1 = [review, review_2, review_3]
+ sum_rating = 0
+ review_count = 0
+ all_reviews_product_1.each do |review|
+ sum_rating += review.rating
+ review_count += 1
+ end
+
+ ave_rating = sum_rating / review_count
+
+ #act
+ #assert
+ product.average_rating.must_equal ave_rating
+ end
+
+ it "returns 0 if no reviews" do
+ Review.destroy_all
+ product = Product.first
+
+ product.average_rating.must_equal 0
+ end
+ end
+
+end
diff --git a/test/models/review_test.rb b/test/models/review_test.rb
new file mode 100644
index 0000000000..a924ec318b
--- /dev/null
+++ b/test/models/review_test.rb
@@ -0,0 +1,51 @@
+require "test_helper"
+
+describe Review do
+ # let(:review) { Review.new }
+ #
+ # it "must be valid" do
+ # value(review).must_be :valid?
+ # end
+ let (:review) {reviews(:review1)}
+ # before do
+ # @review = Review.new
+ # end
+
+ describe "relations" do
+ it "must respond to product" do
+ prod = products(:tricycle)
+
+ review.must_respond_to :product
+ review.product_id.must_equal prod.id
+ review.product.must_equal prod
+ end
+ end
+
+ describe 'validations' do
+ it 'is valid' do
+ review = Review.new(rating: 3, product_id: Product.first.id)
+ review.must_be :valid?
+ end
+
+ it 'requires a rating' do
+ review.rating = nil
+ is_valid = review.valid?
+ is_valid.must_equal false
+ review.errors.messages.must_include :rating
+ end
+
+ it 'requires a ranking greater than 0' do
+ review = Review.new(rating: 0, product_id: 1)
+ is_valid = review.valid?
+ is_valid.must_equal false
+ review.errors.messages.must_include :rating
+ end
+
+ it 'requires a ranking less than 5' do
+ review = Review.new(rating: 6, product_id: 1)
+ is_valid = review.valid?
+ is_valid.must_equal false
+ review.errors.messages.must_include :rating
+ end
+ end
+end
diff --git a/test/system/.keep b/test/system/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test/test_helper.rb b/test/test_helper.rb
new file mode 100644
index 0000000000..3bccaa1199
--- /dev/null
+++ b/test/test_helper.rb
@@ -0,0 +1,50 @@
+require 'simplecov'
+# SimpleCov.start 'rails' unless ENV['NO_COVERAGE']
+SimpleCov.start 'rails'
+ENV["RAILS_ENV"] = "test"
+require File.expand_path("../../config/environment", __FILE__)
+require "rails/test_help"
+require "minitest/rails"
+require "minitest/reporters" # for Colorized output
+
+# For colorful output!
+Minitest::Reporters.use!(
+ Minitest::Reporters::SpecReporter.new,
+ ENV,
+ Minitest.backtrace_filter
+)
+
+# To add Capybara feature tests add `gem "minitest-rails-capybara"`
+# to the test group in the Gemfile and uncomment the following:
+# require "minitest/rails/capybara"
+
+# Uncomment for awesome colorful output
+# require "minitest/pride"
+
+class ActiveSupport::TestCase
+ # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
+ fixtures :all
+ # Add more helper methods to be used by all tests here...
+
+ def setup
+ OmniAuth.config.test_mode = true
+ end
+
+ def mock_auth_hash(merchant)
+ return {
+ provider: merchant.provider,
+ uid: merchant.uid,
+ :info.to_s => {
+ name: merchant.name,
+ email: merchant.email,
+ nickname: merchant.username
+ }
+ }
+ end
+
+ def login(merchant)
+ OmniAuth.config.mock_auth[:github] = OmniAuth::AuthHash.new(mock_auth_hash(merchant))
+ get auth_callback_path(:github)
+ end
+
+end
diff --git a/tmp/.keep b/tmp/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/vendor/.keep b/vendor/.keep
new file mode 100644
index 0000000000..e69de29bb2