diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..34219619b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +/.bundle + +# Ignore all logfiles and tempfiles. +/log/* +/tmp/* +!/log/.keep +!/tmp/.keep + +# Ignore Byebug command history file. +.byebug_history + +# Ignore .DS_Store +.DS_Store +.env + +coverage +#open coverage/index.html diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000000..728773a94b --- /dev/null +++ b/Gemfile @@ -0,0 +1,73 @@ +source 'https://rubygems.org' + +git_source(:github) do |repo_name| + repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") + "https://github.com/#{repo_name}.git" +end + + +# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' +gem 'rails', '~> 5.0.2' +# Use postgresql as the database for Active Record +gem 'pg', '~> 0.18' +# Use Puma as the app server +gem 'puma', '~> 3.0' +# Use SCSS for stylesheets +gem 'sass-rails', '~> 5.0' +# Use Uglifier as compressor for JavaScript assets +gem 'uglifier', '>= 1.3.0' +# Use CoffeeScript for .coffee assets and views +gem 'coffee-rails', '~> 4.2' +# See https://github.com/rails/execjs#readme for more supported runtimes +# gem 'therubyracer', platforms: :ruby + +# Use jquery as the JavaScript library +gem 'jquery-rails' +# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks +gem 'turbolinks', '~> 5' +# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder +gem 'jbuilder', '~> 2.5' +# Use Redis adapter to run Action Cable in production +# gem 'redis', '~> 3.0' +# Use ActiveModel has_secure_password +# gem 'bcrypt', '~> 3.1.7' + +# Use Capistrano for deployment +# gem 'capistrano-rails', group: :development + +group :development, :test do + # Call 'byebug' anywhere in the code to stop execution and get a debugger console + gem 'byebug', platform: :mri +end + +group :development do + # Access an IRB console on exception pages or by using <%= console %> anywhere in the code. + gem 'web-console', '>= 3.3.0' + gem 'listen', '~> 3.0.5' + # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring + gem 'spring' + gem 'spring-watcher-listen', '~> 2.0.0' +end + +# Windows does not include zoneinfo files, so bundle the tzinfo-data gem +gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] + +group :development do + gem 'better_errors' + gem 'pry-rails' + gem 'dotenv-rails' + gem 'binding_of_caller' +end + +gem 'awesome_print' +gem 'foundation-rails' + +gem "omniauth" +gem "omniauth-github" + +gem 'simplecov', :require => false, :group => :test + +group :test do + gem 'minitest-rails' + gem 'minitest-reporters' +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000000..d48114b03f --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,255 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (5.0.2) + actionpack (= 5.0.2) + nio4r (>= 1.2, < 3.0) + websocket-driver (~> 0.6.1) + actionmailer (5.0.2) + actionpack (= 5.0.2) + actionview (= 5.0.2) + activejob (= 5.0.2) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (5.0.2) + actionview (= 5.0.2) + activesupport (= 5.0.2) + rack (~> 2.0) + rack-test (~> 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (5.0.2) + activesupport (= 5.0.2) + builder (~> 3.1) + erubis (~> 2.7.0) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.3) + activejob (5.0.2) + activesupport (= 5.0.2) + globalid (>= 0.3.6) + activemodel (5.0.2) + activesupport (= 5.0.2) + activerecord (5.0.2) + activemodel (= 5.0.2) + activesupport (= 5.0.2) + arel (~> 7.0) + activesupport (5.0.2) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (~> 0.7) + minitest (~> 5.1) + tzinfo (~> 1.1) + ansi (1.5.0) + arel (7.1.4) + awesome_print (1.7.0) + babel-source (5.8.35) + babel-transpiler (0.7.0) + babel-source (>= 4.0, < 6) + execjs (~> 2.0) + better_errors (2.1.1) + coderay (>= 1.0.0) + erubis (>= 2.6.6) + rack (>= 0.9.0) + bindex (0.5.0) + binding_of_caller (0.7.2) + debug_inspector (>= 0.0.1) + builder (3.2.3) + byebug (9.0.6) + coderay (1.1.1) + coffee-rails (4.2.1) + coffee-script (>= 2.2.0) + railties (>= 4.0.0, < 5.2.x) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.12.2) + concurrent-ruby (1.0.5) + debug_inspector (0.0.2) + docile (1.1.5) + dotenv (2.2.0) + dotenv-rails (2.2.0) + dotenv (= 2.2.0) + railties (>= 3.2, < 5.1) + erubis (2.7.0) + execjs (2.7.0) + faraday (0.11.0) + multipart-post (>= 1.2, < 3) + ffi (1.9.18) + foundation-rails (6.3.1.0) + railties (>= 3.1.0) + sass (>= 3.3.0, < 3.5) + sprockets-es6 (>= 0.9.0) + globalid (0.4.0) + activesupport (>= 4.2.0) + hashie (3.5.5) + i18n (0.8.1) + jbuilder (2.6.3) + activesupport (>= 3.0.0, < 5.2) + multi_json (~> 1.2) + jquery-rails (4.3.1) + rails-dom-testing (>= 1, < 3) + railties (>= 4.2.0) + thor (>= 0.14, < 2.0) + json (2.0.2) + jwt (1.5.6) + listen (3.0.8) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + loofah (2.0.3) + nokogiri (>= 1.5.9) + mail (2.6.4) + mime-types (>= 1.16, < 4) + method_source (0.8.2) + mime-types (3.1) + mime-types-data (~> 3.2015) + mime-types-data (3.2016.0521) + mini_portile2 (2.1.0) + minitest (5.10.1) + minitest-rails (3.0.0) + minitest (~> 5.8) + railties (~> 5.0) + minitest-reporters (1.1.14) + ansi + builder + minitest (>= 5.0) + ruby-progressbar + multi_json (1.12.1) + multi_xml (0.6.0) + multipart-post (2.0.0) + nio4r (2.0.0) + nokogiri (1.7.1) + mini_portile2 (~> 2.1.0) + oauth2 (1.3.1) + faraday (>= 0.8, < 0.12) + jwt (~> 1.0) + multi_json (~> 1.3) + multi_xml (~> 0.5) + rack (>= 1.2, < 3) + omniauth (1.6.1) + hashie (>= 3.4.6, < 3.6.0) + rack (>= 1.6.2, < 3) + omniauth-github (1.2.3) + omniauth (~> 1.5) + omniauth-oauth2 (>= 1.4.0, < 2.0) + omniauth-oauth2 (1.4.0) + oauth2 (~> 1.0) + omniauth (~> 1.2) + pg (0.20.0) + pry (0.10.4) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + pry-rails (0.3.6) + pry (>= 0.10.4) + puma (3.8.2) + rack (2.0.1) + rack-test (0.6.3) + rack (>= 1.0) + rails (5.0.2) + actioncable (= 5.0.2) + actionmailer (= 5.0.2) + actionpack (= 5.0.2) + actionview (= 5.0.2) + activejob (= 5.0.2) + activemodel (= 5.0.2) + activerecord (= 5.0.2) + activesupport (= 5.0.2) + bundler (>= 1.3.0, < 2.0) + railties (= 5.0.2) + sprockets-rails (>= 2.0.0) + rails-dom-testing (2.0.2) + activesupport (>= 4.2.0, < 6.0) + nokogiri (~> 1.6) + rails-html-sanitizer (1.0.3) + loofah (~> 2.0) + railties (5.0.2) + actionpack (= 5.0.2) + activesupport (= 5.0.2) + method_source + rake (>= 0.8.7) + thor (>= 0.18.1, < 2.0) + rake (12.0.0) + rb-fsevent (0.9.8) + rb-inotify (0.9.8) + ffi (>= 0.5.0) + ruby-progressbar (1.8.1) + sass (3.4.23) + sass-rails (5.0.6) + railties (>= 4.0.0, < 6) + sass (~> 3.1) + sprockets (>= 2.8, < 4.0) + sprockets-rails (>= 2.0, < 4.0) + tilt (>= 1.1, < 3) + simplecov (0.13.0) + docile (~> 1.1.0) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.0) + slop (3.6.0) + spring (2.0.1) + activesupport (>= 4.2) + spring-watcher-listen (2.0.1) + listen (>= 2.7, < 4.0) + spring (>= 1.2, < 3.0) + sprockets (3.7.1) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-es6 (0.9.2) + babel-source (>= 5.8.11) + babel-transpiler + sprockets (>= 3.0.0) + sprockets-rails (3.2.0) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + thor (0.19.4) + thread_safe (0.3.6) + tilt (2.0.7) + turbolinks (5.0.1) + turbolinks-source (~> 5) + turbolinks-source (5.0.0) + tzinfo (1.2.3) + thread_safe (~> 0.1) + uglifier (3.2.0) + execjs (>= 0.3.0, < 3) + web-console (3.5.0) + actionview (>= 5.0) + activemodel (>= 5.0) + bindex (>= 0.4.0) + railties (>= 5.0) + websocket-driver (0.6.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.2) + +PLATFORMS + ruby + +DEPENDENCIES + awesome_print + better_errors + binding_of_caller + byebug + coffee-rails (~> 4.2) + dotenv-rails + foundation-rails + jbuilder (~> 2.5) + jquery-rails + listen (~> 3.0.5) + minitest-rails + minitest-reporters + omniauth + omniauth-github + pg (~> 0.18) + pry-rails + puma (~> 3.0) + rails (~> 5.0.2) + sass-rails (~> 5.0) + simplecov + spring + spring-watcher-listen (~> 2.0.0) + turbolinks (~> 5) + tzinfo-data + uglifier (>= 1.3.0) + web-console (>= 3.3.0) + +BUNDLED WITH + 1.14.6 diff --git a/README.md b/README.md index 2ddf2f5127..581c6341ec 100644 --- a/README.md +++ b/README.md @@ -24,17 +24,20 @@ - You must use oAuth for user authentication. ## Getting Started -1. As a group decide on an app name (this may help lead the aesthetic) -1. As a group decide on a team name (this will amuse your instructors) -1. Have one person on your team fork/clone the project master as per usual - 1. Create a new rails app using `rails new .` - 1. Add all other team members as collaborators - 1. Each team member should clone the repo to their computer +> 1. As a group decide on an app name (this may help lead the aesthetic) +> 1. As a group decide on a team name (this will amuse your instructors) +> 1. Have one person on your team fork/clone the project master as per usual +> 1. Create a new rails app using `rails new .` +> 1. Add all other team members as collaborators +> 1. Each team member should clone the repo to their computer 1. Figure out your workflow for the project, re: Git and Task management - 1. Determine who will be the Stand Up Leader and Task Leader for the first week -1. Create a Trello board and ensure that all team members and instructors have access -1. Review the User Stories below and create Trello tasks to represent them -1. Slack your team name, app name, and link to your trello board to your Project Manager + - avoid working on the same file as a team member + - avoid merging to master at night + - branch naming convention: initials/branch_name +> 1. Determine who will be the Stand Up Leader and Task Leader for the first week +> 1. Create a Trello board and ensure that all team members and instructors have access +> 1. Review the User Stories below and create Trello tasks to represent them +> 1. Slack your team name, app name, and link to your trello board to your Project Manager ## Expectations Build an online system for listing, selling, reviewing, and buying a wide variety of products listed by multiple merchants. @@ -50,34 +53,34 @@ Build an online system for listing, selling, reviewing, and buying a wide variet #### Guest User (Unauthenticated) As a guest to the website (not signed in) I **can**: -- Browse all products -- Browse products by category -- Browse products by merchant (users) -- View any individual product with additional details -- Leave a review for a product providing: - - A Text review - - A rating out of 5 -- Add in-stock products to my cart -- Remove products from my cart -- Change the quantity of an existing product in my cart -- Purchase the items in my cart, providing: - - Email Address - - Mailing Address - - Name on credit card - - Credit card number - - Credit cart expiration - - Credit Card CVV (security code) - - Billing zip code -- Purchasing an order makes the following changes: - - Reduces the number of inventory for each product - - Changes the order state from "pending" to "paid" - - Clears the current cart -- After purchasing an order, I can view a confirmation screen including: - - Each item in the order with a quantity and line-item subtotal - - A link to the item description page - - Order total price - - DateTime the order was placed - - The current status of the order +> - Browse all products ** +> - Browse products by category +> - Browse products by merchant (users) +> - View any individual product with additional details +> - Leave a review for a product providing: + > - A Text review + >- A rating out of 5 +> - Add in-stock products to my cart +> - Remove products from my cart +> - Change the quantity of an existing product in my cart +> - Purchase the items in my cart, providing: + > Email Address + > - Mailing Address + > - Name on credit card + > - Credit card number + > - Credit cart expiration + > - Credit Card CVV (security code) + > - Billing zip code +> - Purchasing an order makes the following changes: + > - Reduces the number of inventory for each product + > - Changes the order state from "pending" to "paid" + > - Clears the current cart +> - After purchasing an order, I can view a confirmation screen including: + > - Each item in the order with a quantity and line-item subtotal + > - A link to the item description page + > - Order total price + > - DateTime the order was placed + > - The current status of the order - Sign up to be a merchant using OAuth - Every merchant must have a username - Sign in to my merchant account using OAuth diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000000..e85f913914 --- /dev/null +++ b/Rakefile @@ -0,0 +1,6 @@ +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require_relative 'config/application' + +Rails.application.load_tasks diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js new file mode 100644 index 0000000000..b16e53d6d5 --- /dev/null +++ b/app/assets/config/manifest.js @@ -0,0 +1,3 @@ +//= link_tree ../images +//= link_directory ../javascripts .js +//= link_directory ../stylesheets .css diff --git a/app/assets/images/.keep b/app/assets/images/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/assets/images/cart.png b/app/assets/images/cart.png new file mode 100644 index 0000000000..502026cfc4 Binary files /dev/null and b/app/assets/images/cart.png differ diff --git a/app/assets/images/dandelion.jpg b/app/assets/images/dandelion.jpg new file mode 100644 index 0000000000..17c9186752 Binary files /dev/null and b/app/assets/images/dandelion.jpg differ diff --git a/app/assets/images/flower.png b/app/assets/images/flower.png new file mode 100644 index 0000000000..dacc12a5fd Binary files /dev/null and b/app/assets/images/flower.png differ diff --git a/app/assets/images/meadow.jpg b/app/assets/images/meadow.jpg new file mode 100644 index 0000000000..3e988e7d76 Binary files /dev/null and b/app/assets/images/meadow.jpg differ diff --git a/app/assets/images/tommy.jpg b/app/assets/images/tommy.jpg new file mode 100644 index 0000000000..26d90ce4ba Binary files /dev/null and b/app/assets/images/tommy.jpg differ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js new file mode 100644 index 0000000000..32980d96f3 --- /dev/null +++ b/app/assets/javascripts/application.js @@ -0,0 +1,19 @@ +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// compiled file. JavaScript code in this file should be added after the last require_* statement. +// +// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details +// about supported directives. +// +//= require jquery +//= require jquery_ujs +//= require foundation +//= require turbolinks +//= require_tree . + +$(function(){ $(document).foundation(); }); diff --git a/app/assets/javascripts/cable.js b/app/assets/javascripts/cable.js new file mode 100644 index 0000000000..71ee1e66de --- /dev/null +++ b/app/assets/javascripts/cable.js @@ -0,0 +1,13 @@ +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the rails generate channel command. +// +//= require action_cable +//= require_self +//= require_tree ./channels + +(function() { + this.App || (this.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); diff --git a/app/assets/javascripts/categories.coffee b/app/assets/javascripts/categories.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/categories.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/channels/.keep b/app/assets/javascripts/channels/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/assets/javascripts/items.coffee b/app/assets/javascripts/items.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/items.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/merchants.coffee b/app/assets/javascripts/merchants.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/merchants.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/orders.coffee b/app/assets/javascripts/orders.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/orders.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/payments.coffee b/app/assets/javascripts/payments.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/payments.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/reviews.coffee b/app/assets/javascripts/reviews.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/reviews.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/sessions.coffee b/app/assets/javascripts/sessions.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/sessions.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/_settings.scss b/app/assets/stylesheets/_settings.scss new file mode 100644 index 0000000000..04de9effca --- /dev/null +++ b/app/assets/stylesheets/_settings.scss @@ -0,0 +1,620 @@ +// Foundation for Sites Settings +// ----------------------------- +// +// Table of Contents: +// +// 1. Global +// 2. Breakpoints +// 3. The Grid +// 4. Base Typography +// 5. Typography Helpers +// 6. Abide +// 7. Accordion +// 8. Accordion Menu +// 9. Badge +// 10. Breadcrumbs +// 11. Button +// 12. Button Group +// 13. Callout +// 14. Card +// 15. Close Button +// 16. Drilldown +// 17. Dropdown +// 18. Dropdown Menu +// 19. Forms +// 20. Label +// 21. Media Object +// 22. Menu +// 23. Meter +// 24. Off-canvas +// 25. Orbit +// 26. Pagination +// 27. Progress Bar +// 28. Responsive Embed +// 29. Reveal +// 30. Slider +// 31. Switch +// 32. Table +// 33. Tabs +// 34. Thumbnail +// 35. Title Bar +// 36. Tooltip +// 37. Top Bar + +@import 'util/util'; + +// 1. Global +// --------- + +$global-font-size: 100%; +$global-width: rem-calc(1200); +$global-lineheight: 1.5; +$foundation-palette: ( + primary: #1F5673, + secondary: #1F5673, + success: #1F5673, + warning: #ffae00, + alert: #EEECEC, +); +$light-gray: #e6e6e6; +$medium-gray: #cacaca; +$dark-gray: #8a8a8a; +$black: #0a0a0a; +$white: #fefefe; +$body-background: #EAF4F5; +$body-font-color: #CCD0C9; +$body-font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; +$body-antialiased: true; +$global-margin: 1rem; +$global-padding: 1rem; +$global-weight-normal: normal; +$global-weight-bold: bold; +$global-radius: 0; +$global-text-direction: ltr; +$global-flexbox: false; +$print-transparent-backgrounds: true; + +@include add-foundation-colors; + +// 2. Breakpoints +// -------------- + +$breakpoints: ( + small: 0, + medium: 640px, + large: 1024px, + xlarge: 1200px, + xxlarge: 1440px, +); +$print-breakpoint: large; +$breakpoint-classes: (small medium large); + +// 3. The Grid +// ----------- + +$grid-row-width: $global-width; +$grid-column-count: 12; +$grid-column-gutter: ( + small: 20px, + medium: 30px, +); +$grid-column-align-edge: true; +$block-grid-max: 8; + +// 4. Base Typography +// ------------------ + +$header-font-family: $body-font-family; +$header-font-weight: $global-weight-normal; +$header-font-style: normal; +$font-family-monospace: Consolas, 'Liberation Mono', Courier, monospace; +$header-color: #CCD0C9; +$header-lineheight: 1.4; +$header-margin-bottom: 0.5rem; +$header-styles: ( + small: ( + 'h1': ('font-size': 24), + 'h2': ('font-size': 20), + 'h3': ('font-size': 19), + 'h4': ('font-size': 18), + 'h5': ('font-size': 17), + 'h6': ('font-size': 16), + ), + medium: ( + 'h1': ('font-size': 48), + 'h2': ('font-size': 40), + 'h3': ('font-size': 31), + 'h4': ('font-size': 25), + 'h5': ('font-size': 20), + 'h6': ('font-size': 16), + ), +); +$header-text-rendering: optimizeLegibility; +$small-font-size: 80%; +$header-small-font-color: #CCD0C9; +$paragraph-lineheight: 1.6; +$paragraph-margin-bottom: 1rem; +$paragraph-text-rendering: optimizeLegibility; +$code-color: $black; +$code-font-family: $font-family-monospace; +$code-font-weight: $global-weight-normal; +$code-background: $light-gray; +$code-border: 1px solid $medium-gray; +$code-padding: rem-calc(2 5 1); +$anchor-color: $primary-color; +$anchor-color-hover: scale-color($anchor-color, $lightness: -14%); +$anchor-text-decoration: none; +$anchor-text-decoration-hover: none; +$hr-width: $global-width; +$hr-border: 1px solid $medium-gray; +$hr-margin: rem-calc(20) auto; +$list-lineheight: $paragraph-lineheight; +$list-margin-bottom: $paragraph-margin-bottom; +$list-style-type: disc; +$list-style-position: outside; +$list-side-margin: 1.25rem; +$list-nested-side-margin: 1.25rem; +$defnlist-margin-bottom: 1rem; +$defnlist-term-weight: $global-weight-bold; +$defnlist-term-margin-bottom: 0.3rem; +$blockquote-color: #CCD0C9; +$blockquote-padding: rem-calc(9 20 0 19); +$blockquote-border: 1px solid $medium-gray; +$cite-font-size: rem-calc(13); +$cite-color: #CCD0C9; +$cite-pseudo-content: '\2014 \0020'; +$keystroke-font: $font-family-monospace; +$keystroke-color: $black; +$keystroke-background: $light-gray; +$keystroke-padding: rem-calc(2 4 0); +$keystroke-radius: $global-radius; +$abbr-underline: 1px dotted $black; + +// 5. Typography Helpers +// --------------------- + +$lead-font-size: $global-font-size * 1.25; +$lead-lineheight: 1.6; +$subheader-lineheight: 1.4; +$subheader-color: #CCD0C9; +$subheader-font-weight: $global-weight-normal; +$subheader-margin-top: 0.2rem; +$subheader-margin-bottom: 0.5rem; +$stat-font-size: 2.5rem; + +// 6. Abide +// -------- + +$abide-inputs: true; +$abide-labels: true; +$input-background-invalid: get-color(alert); +$form-label-color-invalid: get-color(alert); +$input-error-color: get-color(alert); +$input-error-font-size: rem-calc(12); +$input-error-font-weight: $global-weight-bold; + +// 7. Accordion +// ------------ + +$accordion-background: $white; +$accordion-plusminus: true; +$accordion-title-font-size: rem-calc(12); +$accordion-item-color: $primary-color; +$accordion-item-background-hover: #EEECEC; +$accordion-item-padding: 1.25rem 1rem; +$accordion-content-background: $white; +$accordion-content-border: 1px solid $light-gray; +$accordion-content-color: $body-font-color; +$accordion-content-padding: 1rem; + +// 8. Accordion Menu +// ----------------- + +$accordionmenu-arrows: true; +$accordionmenu-arrow-color: $primary-color; +$accordionmenu-arrow-size: 6px; + +// 9. Badge +// -------- + +$badge-background: $primary-color; +$badge-color: $white; +$badge-color-alt: $black; +$badge-palette: $foundation-palette; +$badge-padding: 0.3em; +$badge-minwidth: 2.1em; +$badge-font-size: 0.6rem; + +// 10. Breadcrumbs +// --------------- + +$breadcrumbs-margin: 0 0 $global-margin 0; +$breadcrumbs-item-font-size: rem-calc(11); +$breadcrumbs-item-color: $primary-color; +$breadcrumbs-item-color-current: $black; +$breadcrumbs-item-color-disabled: $medium-gray; +$breadcrumbs-item-margin: 0.75rem; +$breadcrumbs-item-uppercase: true; +$breadcrumbs-item-slash: true; + +// 11. Button +// ---------- + +$button-padding: 0.85em 1em; +$button-margin: 0 0 $global-margin 0; +$button-fill: solid; +$button-background: $primary-color; +$button-background-hover: scale-color($button-background, $lightness: -15%); +$button-color: $white; +$button-color-alt: $black; +$button-radius: $global-radius; +$button-sizes: ( + tiny: 0.6rem, + small: 0.75rem, + default: 0.9rem, + large: 1.25rem, +); +$button-palette: $foundation-palette; +$button-opacity-disabled: 0.25; +$button-background-hover-lightness: -20%; +$button-hollow-hover-lightness: -50%; +$button-transition: background-color 0.25s ease-out, color 0.25s ease-out; + +// 12. Button Group +// ---------------- + +$buttongroup-margin: 1rem; +$buttongroup-spacing: 1px; +$buttongroup-child-selector: '.button'; +$buttongroup-expand-max: 6; +$buttongroup-radius-on-each: true; + +// 13. Callout +// ----------- + +$callout-background: $white; +$callout-background-fade: 85%; +$callout-border: 1px solid rgba($black, 0.25); +$callout-margin: 0 0 1rem 0; +$callout-padding: 1rem; +$callout-font-color: $body-font-color; +$callout-font-color-alt: $body-background; +$callout-radius: $global-radius; +$callout-link-tint: 30%; + +// 14. Card +// -------- + +$card-background: $white; +$card-font-color: $body-font-color; +$card-divider-background: $light-gray; +$card-border: 1px solid $light-gray; +$card-shadow: none; +$card-border-radius: $global-radius; +$card-padding: $global-padding; +$card-margin: $global-margin; + +// 15. Close Button +// ---------------- + +$closebutton-position: right top; +$closebutton-offset-horizontal: ( + small: 0.66rem, + medium: 1rem, +); +$closebutton-offset-vertical: ( + small: 0.33em, + medium: 0.5rem, +); +$closebutton-size: ( + small: 1.5em, + medium: 2em, +); +$closebutton-lineheight: 1; +$closebutton-color: $dark-gray; +$closebutton-color-hover: $black; + +// 16. Drilldown +// ------------- + +$drilldown-transition: transform 0.15s linear; +$drilldown-arrows: true; +$drilldown-arrow-color: $primary-color; +$drilldown-arrow-size: 6px; +$drilldown-background: $white; + +// 17. Dropdown +// ------------ + +$dropdown-padding: 1rem; +$dropdown-background: $body-background; +$dropdown-border: 1px solid #EEECEC; +$dropdown-font-size: 3rem; +$dropdown-width: 300px; +$dropdown-radius: $global-radius; +$dropdown-sizes: ( + tiny: 100px, + small: 200px, + large: 400px, +); + +// 18. Dropdown Menu +// ----------------- + +$dropdownmenu-arrows: true; +$dropdownmenu-arrow-color: $anchor-color; +$dropdownmenu-arrow-size: 6px; +$dropdownmenu-min-width: 200px; +$dropdownmenu-background: $white; +$dropdownmenu-border: 1px solid $medium-gray; + +// 19. Forms +// --------- + +$fieldset-border: 1px solid $medium-gray; +$fieldset-padding: rem-calc(20); +$fieldset-margin: rem-calc(18 0); +$legend-padding: rem-calc(0 3); +$form-spacing: rem-calc(16); +$helptext-color: #CCD0C9; +$helptext-font-size: rem-calc(13); +$helptext-font-style: italic; +$input-prefix-color: #1F5673; +$input-prefix-background: $light-gray; +$input-prefix-border: 1px solid $medium-gray; +$input-prefix-padding: 1rem; +$form-label-color: #CCD0C9; +$form-label-font-size: rem-calc(30); +$form-label-font-weight: $global-weight-normal; +$form-label-line-height: 1.8; +$select-background: $white; +$select-triangle-color: $dark-gray; +$select-radius: $global-radius; +$input-color: #233B64; +$input-placeholder-color: $medium-gray; +$input-font-family: inherit; +$input-font-size: rem-calc(25); +$input-font-weight: $global-weight-normal; +$input-background: $white; +$input-background-focus: $white; +$input-background-disabled: $light-gray; +$input-border: 1px solid $medium-gray; +$input-border-focus: 1px solid $dark-gray; +$input-shadow: inset 0 1px 2px rgba($black, 0.1); +$input-shadow-focus: 0 0 5px $medium-gray; +$input-cursor-disabled: not-allowed; +$input-transition: box-shadow 0.5s, border-color 0.25s ease-in-out; +$input-number-spinners: true; +$input-radius: $global-radius; +$form-button-radius: $global-radius; + +// 20. Label +// --------- + +$label-background: $primary-color; +$label-color: $white; +$label-color-alt: $black; +$label-palette: $foundation-palette; +$label-font-size: 0.8rem; +$label-padding: 0.33333rem 0.5rem; +$label-radius: $global-radius; + +// 21. Media Object +// ---------------- + +$mediaobject-margin-bottom: $global-margin; +$mediaobject-section-padding: $global-padding; +$mediaobject-image-width-stacked: 100%; + +// 22. Menu +// -------- + +$menu-margin: 0; +$menu-margin-nested: 1rem; +$menu-item-padding: 0.7rem 1rem; +$menu-item-color-active: $white; +$menu-item-background-active: get-color(primary); +$menu-icon-spacing: 0.25rem; +$menu-item-background-hover: $light-gray; +$menu-border: $light-gray; + +// 23. Meter +// --------- + +$meter-height: 1rem; +$meter-radius: $global-radius; +$meter-background: $medium-gray; +$meter-fill-good: $success-color; +$meter-fill-medium: $warning-color; +$meter-fill-bad: $alert-color; + +// 24. Off-canvas +// -------------- + +$offcanvas-size: 250px; +$offcanvas-vertical-size: 250px; +$offcanvas-background: $light-gray; +$offcanvas-shadow: 0 0 10px rgba($black, 0.7); +$offcanvas-push-zindex: 1; +$offcanvas-overlap-zindex: 10; +$offcanvas-reveal-zindex: 1; +$offcanvas-transition-length: 0.5s; +$offcanvas-transition-timing: ease; +$offcanvas-fixed-reveal: true; +$offcanvas-exit-background: rgba($white, 0.25); +$maincontent-class: 'off-canvas-content'; + +// 25. Orbit +// --------- + +$orbit-bullet-background: $medium-gray; +$orbit-bullet-background-active: $dark-gray; +$orbit-bullet-diameter: 1.2rem; +$orbit-bullet-margin: 0.1rem; +$orbit-bullet-margin-top: 0.8rem; +$orbit-bullet-margin-bottom: 0.8rem; +$orbit-caption-background: rgba($black, 0.5); +$orbit-caption-padding: 1rem; +$orbit-control-background-hover: rgba($black, 0.5); +$orbit-control-padding: 1rem; +$orbit-control-zindex: 10; + +// 26. Pagination +// -------------- + +$pagination-font-size: rem-calc(14); +$pagination-margin-bottom: $global-margin; +$pagination-item-color: $black; +$pagination-item-padding: rem-calc(3 10); +$pagination-item-spacing: rem-calc(1); +$pagination-radius: $global-radius; +$pagination-item-background-hover: $light-gray; +$pagination-item-background-current: $primary-color; +$pagination-item-color-current: $white; +$pagination-item-color-disabled: $medium-gray; +$pagination-ellipsis-color: $black; +$pagination-mobile-items: false; +$pagination-mobile-current-item: false; +$pagination-arrows: true; + +// 27. Progress Bar +// ---------------- + +$progress-height: 1rem; +$progress-background: $medium-gray; +$progress-margin-bottom: $global-margin; +$progress-meter-background: $primary-color; +$progress-radius: $global-radius; + +// 28. Responsive Embed +// -------------------- + +$responsive-embed-margin-bottom: rem-calc(16); +$responsive-embed-ratios: ( + default: 4 by 3, + widescreen: 16 by 9, +); + +// 29. Reveal +// ---------- + +$reveal-background: $white; +$reveal-width: 600px; +$reveal-max-width: $global-width; +$reveal-padding: $global-padding; +$reveal-border: 1px solid $medium-gray; +$reveal-radius: $global-radius; +$reveal-zindex: 1005; +$reveal-overlay-background: rgba($black, 0.45); + +// 30. Slider +// ---------- + +$slider-width-vertical: 0.5rem; +$slider-transition: all 0.2s ease-in-out; +$slider-height: 0.5rem; +$slider-background: $light-gray; +$slider-fill-background: $medium-gray; +$slider-handle-height: 1.4rem; +$slider-handle-width: 1.4rem; +$slider-handle-background: $primary-color; +$slider-opacity-disabled: 0.25; +$slider-radius: $global-radius; + +// 31. Switch +// ---------- + +$switch-background: $medium-gray; +$switch-background-active: $primary-color; +$switch-height: 2rem; +$switch-height-tiny: 1.5rem; +$switch-height-small: 1.75rem; +$switch-height-large: 2.5rem; +$switch-radius: $global-radius; +$switch-margin: $global-margin; +$switch-paddle-background: $white; +$switch-paddle-offset: 0.25rem; +$switch-paddle-radius: $global-radius; +$switch-paddle-transition: all 0.25s ease-out; + +// 32. Table +// --------- + +$table-background: $white; +$table-color-scale: 5%; +$table-border: 1px solid smart-scale($table-background, $table-color-scale); +$table-padding: rem-calc(8 10 10); +$table-hover-scale: 2%; +$table-row-hover: darken($table-background, $table-hover-scale); +$table-row-stripe-hover: darken($table-background, $table-color-scale + $table-hover-scale); +$table-is-striped: true; +$table-striped-background: smart-scale($table-background, $table-color-scale); +$table-stripe: even; +$table-head-background: smart-scale($table-background, $table-color-scale / 2); +$table-head-row-hover: darken($table-head-background, $table-hover-scale); +$table-foot-background: smart-scale($table-background, $table-color-scale); +$table-foot-row-hover: darken($table-foot-background, $table-hover-scale); +$table-head-font-color: $body-font-color; +$table-foot-font-color: $body-font-color; +$show-header-for-stacked: false; + +// 33. Tabs +// -------- + +$tab-margin: 0; +$tab-background: $white; +$tab-color: $primary-color; +$tab-background-active: $light-gray; +$tab-active-color: $primary-color; +$tab-item-font-size: rem-calc(12); +$tab-item-background-hover: $white; +$tab-item-padding: 1.25rem 1.5rem; +$tab-expand-max: 6; +$tab-content-background: $white; +$tab-content-border: $light-gray; +$tab-content-color: $body-font-color; +$tab-content-padding: 1rem; + +// 34. Thumbnail +// ------------- + +$thumbnail-border: solid 4px $white; +$thumbnail-margin-bottom: $global-margin; +$thumbnail-shadow: 0 0 0 1px rgba($black, 0.2); +$thumbnail-shadow-hover: 0 0 6px 1px rgba($primary-color, 0.5); +$thumbnail-transition: box-shadow 200ms ease-out; +$thumbnail-radius: $global-radius; + +// 35. Title Bar +// ------------- + +$titlebar-background: $black; +$titlebar-color: $white; +$titlebar-padding: 0.5rem; +$titlebar-text-font-weight: bold; +$titlebar-icon-color: $white; +$titlebar-icon-color-hover: $medium-gray; +$titlebar-icon-spacing: 0.25rem; + +// 36. Tooltip +// ----------- + +$has-tip-font-weight: $global-weight-bold; +$has-tip-border-bottom: dotted 1px $dark-gray; +$tooltip-background-color: $black; +$tooltip-color: $white; +$tooltip-padding: 0.75rem; +$tooltip-font-size: $small-font-size; +$tooltip-pip-width: 0.75rem; +$tooltip-pip-height: $tooltip-pip-width * 0.866; +$tooltip-radius: $global-radius; + +// 37. Top Bar +// ----------- + +$topbar-padding: 0.5rem; +$topbar-background: $light-gray; +$topbar-submenu-background: $topbar-background; +$topbar-title-spacing: 0.5rem 1rem 0.5rem 0; +$topbar-input-width: 200px; +$topbar-unstack-breakpoint: medium; diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css new file mode 100644 index 0000000000..1743bce877 --- /dev/null +++ b/app/assets/stylesheets/application.css @@ -0,0 +1,219 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, + * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the bottom of the + * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS + * files in this directory. Styles in this file should be added after the last require_* statement. + * It is generally better to create a new file per style scope. + * + *= require_tree . + *= require_self + *= require foundation_and_overrides + + */ + /* Dropdown Button */ + + /*header { + /*background-color: #a99ed8;*/ + /*clear: both;*/ + /*color: white;*/ + /*} + + + header h1 { + font-size: 3em; + margin: 0px; + } + + */ + + + +.callout { + background: rgba(240,230,220, .6); + } + + .callout:hover { + background: rgba(240,230,220, .8); + } + +header h1 { + text-shadow: 0 2px 2px #000; +} + + ul { + list-style: none; + } + + li a { + color: #CCD0C9; + font-size: 2em; + text-shadow: 0 2px 2px #000; + } + + + html * { + font-family: 'Give You Glory', cursive; + } + +header h1 a { + font-size: 70px; + color: #CCD0C9; + +} + +header h1 a:hover { + font-size: 70px; + color: #CCD0C9; + text-shadow: 0 10px 10px #000; +} + +h1.package{ + text-shadow: 0 2px 2px #000; +} + + nav { + text-align: center; + }/* + + +input { + /*background-color: #f9f9ff;*/ + /*border-radius: 5px; +}*/ + +/*input:hover { + /*background-color: #bbb1e7; +}*/ + + nav div button.dropbtn { + /*background-color: lightgrey;*/ + /*color: white;*/ + text-shadow: 0 2px 2px #000; + padding: 16px; + font-size: 25px; + border: none; + cursor: pointer; + color: #CCD0C9; + + } + + /* The container
- needed to position the dropdown content */ + nav div.dropdown { + position: relative; + display: inline-block; + background-color: none; + + } + + /* Dropdown Content (Hidden by Default) */ + .dropdown-content { + display: none; + position: absolute; + background-color: #CCD0C9; + min-width: 170px; + box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); + z-index: 1; + + } + + /* Links inside the dropdown */ + .dropdown-content a { + padding: 12px 16px; + text-decoration: none; + display: block; + color: #233B64; + } + + .dropbtn a { + color: #CCD0C9; + text-decoration: none; + + } + .dropbtn a:hover { + color: #CCD0C9; + text-decoration: none; + text-shadow: 0 4px 4px #000; + background-color: none; + } + + + /* Change color of dropdown links on hover */ + .dropdown-content a:hover { + background-color: #233B64; + color: #CCD0C9; + + + } + + .cart_quantity { + display: inline-block; + } + +.cart { + height: 2em; +} + /* Show the dropdown menu on hover */ + .dropdown:hover .dropdown-content { + display: block; + } + + /* Change the background color of the dropdown button when the dropdown content is shown */ + .dropdown:hover .dropbtn { + background-color: #233B64; + + } + + +/*.button { + padding: 16px; + font-size: 25px; + border: 1px; + cursor: pointer; + color: #CCD0C9; +}*/ + + +.button a { + color: #CCD0C9; +} + +h5.main_page { + color: #233B64; +} + +/*footer { + text-shadow: 0 2px 2px #000; + position: absolute; + left: 0; + bottom: 0; + height: 100px; + width: 100%; + overflow:hidden; +}*/ + +footer { + padding-top: 10em; + bottom: 0; + height: 100px; + left: 0; + position: absolute; + width: 100%; +} + +#main-wrapper { + display: flex; + flex-direction: column; + min-height: 100%; +} + +html, +body { + height: 100%; + margin: 0; + padding: 0; +} diff --git a/app/assets/stylesheets/categories.scss b/app/assets/stylesheets/categories.scss new file mode 100644 index 0000000000..42976cbc11 --- /dev/null +++ b/app/assets/stylesheets/categories.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Categories controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/foundation_and_overrides.scss b/app/assets/stylesheets/foundation_and_overrides.scss new file mode 100644 index 0000000000..2066155081 --- /dev/null +++ b/app/assets/stylesheets/foundation_and_overrides.scss @@ -0,0 +1,53 @@ +@charset 'utf-8'; + +@import 'settings'; +@import 'foundation'; + +// If you'd like to include motion-ui the foundation-rails gem comes prepackaged with it, uncomment the 3 @imports, if you are not using the gem you need to install the motion-ui sass package. +// +// @import 'motion-ui/motion-ui'; + +// We include everything by default. To slim your CSS, remove components you don't use. + +@include foundation-global-styles; +@include foundation-grid; +@include foundation-typography; +@include foundation-button; +@include foundation-forms; +@include foundation-visibility-classes; +@include foundation-float-classes; +@include foundation-accordion; +@include foundation-accordion-menu; +@include foundation-badge; +@include foundation-breadcrumbs; +@include foundation-button-group; +@include foundation-callout; +@include foundation-card; +@include foundation-close-button; +@include foundation-drilldown-menu; +@include foundation-dropdown; +@include foundation-dropdown-menu; +@include foundation-responsive-embed; +@include foundation-label; +@include foundation-media-object; +@include foundation-menu; +@include foundation-menu-icon; +@include foundation-off-canvas; +@include foundation-orbit; +@include foundation-pagination; +@include foundation-progress-bar; +@include foundation-slider; +@include foundation-sticky; +@include foundation-reveal; +@include foundation-switch; +@include foundation-table; +@include foundation-tabs; +@include foundation-thumbnail; +@include foundation-title-bar; +@include foundation-tooltip; +@include foundation-top-bar; + +// If you'd like to include motion-ui the foundation-rails gem comes prepackaged with it, uncomment the 3 @imports, if you are not using the gem you need to install the motion-ui sass package. +// +// @include motion-ui-transitions; +// @include motion-ui-animations; diff --git a/app/assets/stylesheets/items.scss b/app/assets/stylesheets/items.scss new file mode 100644 index 0000000000..c6c60119a8 --- /dev/null +++ b/app/assets/stylesheets/items.scss @@ -0,0 +1,21 @@ +// Place all the styles related to the Items controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ + +body { + text-align: center; + background-image: asset_url("dandelion.jpg"); + background-size: cover +} + + +// footer { +// text-shadow: 0 2px 2px #000; +// position: absolute; +// left: 0; +// bottom: 0; +// height: 100px; +// width: 100%; +// overflow:hidden; +// color: white; +// } diff --git a/app/assets/stylesheets/merchants.scss b/app/assets/stylesheets/merchants.scss new file mode 100644 index 0000000000..e3a4033304 --- /dev/null +++ b/app/assets/stylesheets/merchants.scss @@ -0,0 +1,12 @@ +// Place all the styles related to the Merchants controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ +table, th, td { + color: #233B64; + font-size: 24px; +} + +h4 { + text-align: left; + font-weight: bold; +} diff --git a/app/assets/stylesheets/orders.scss b/app/assets/stylesheets/orders.scss new file mode 100644 index 0000000000..741506954d --- /dev/null +++ b/app/assets/stylesheets/orders.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Orders controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/payments.scss b/app/assets/stylesheets/payments.scss new file mode 100644 index 0000000000..09456e257d --- /dev/null +++ b/app/assets/stylesheets/payments.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Payments controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/reviews.scss b/app/assets/stylesheets/reviews.scss new file mode 100644 index 0000000000..11bbb12cd5 --- /dev/null +++ b/app/assets/stylesheets/reviews.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Reviews controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/sessions.scss b/app/assets/stylesheets/sessions.scss new file mode 100644 index 0000000000..ccb1ed25b2 --- /dev/null +++ b/app/assets/stylesheets/sessions.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Sessions controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000000..d672697283 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000000..0ff5442f47 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 0000000000..7d2c22a16a --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,59 @@ +class ApplicationController < ActionController::Base + protect_from_forgery with: :exception + before_action :add_header_text + helper_method :current_merchant + before_action :require_login, :require_user + before_action :cart_quantity + + + + def add_header_text + @categories = Category.all + @merchants = Merchant.all + end + + def require_login + if !session[:merchant_id] + flash[:warning] = "You must be logged in to view this page" + redirect_to items_path + end + end + + def require_user + if !session[:merchant_id] + if !session[:id] + if Order.all.length == 0 + session[:id] = 1 + @order = Order.new + @order.save + @order.session_id = 1 + else + @order = Order.new + session[:id] = Order.last.session_id + 1 + @order.id = (Order.last.id + 1) + @order.status = "pending" + @order.session_id = session[:id] + @order.total = 0 + @order.save + # raise + end + end + end + end + + def cart_quantity + order = Order.where(session_id: session[:id]) + order_items = OrderItem.where(order_id: order.ids.last) + @cart_quantity = order_items.length + end + + def render_404 + render file: "#{ Rails.root }/public/404.html", status: 404 + end + + def current_merchant + if session[:merchant_id] + @login_merchant = Merchant.find_by(id: session[:merchant_id]) + end + end +end diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb new file mode 100644 index 0000000000..9e2714b083 --- /dev/null +++ b/app/controllers/categories_controller.rb @@ -0,0 +1,43 @@ +class CategoriesController < ApplicationController + skip_before_action :require_login, only: [:index, :show] + + def new + @category = Category.new + end + + def create + @category = Category.new(category_params) + if @category.save + flash[:success] = "New #{@category.name} cateogry has been successfully created" + redirect_to root_path + else + flash[:error] = "Category could not be created" + @category.errors.messages + render 'new' + end + end + + def index + @categories = Category.all + end + + # def show + # @items = Category.find_by(@item_category) + # if !@items + # render_404 + # end + # end + + # + # @category = Category.find_by_id(params[:id]) + # if !@category + # render_404 + # end + # end + + private + def category_params + params.require(:category).permit(:name) + end + +end diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/controllers/items_controller.rb b/app/controllers/items_controller.rb new file mode 100644 index 0000000000..78f179cc4b --- /dev/null +++ b/app/controllers/items_controller.rb @@ -0,0 +1,226 @@ +class ItemsController < ApplicationController + + skip_before_action :require_login, only: [:index, :show, :add_to_cart, :show_cart, :root, :update_cart, :remove_from_cart] + + + # Price must be a number + # Price must be greater than 0 + before_action :find_categories, only: [:show, :edit] + + def root + @featured_items = Item.all.sample(3) + end + + def index + if params[:category_id] + # we are in the nested route + @items = Item.includes(:categories).where(categories: { id: params[:category_id]}) + hide_retired + if current_merchant + @items = @items.where(merchant_id: current_merchant.id) + end + # raise + else + # we are in our 'regular' route + @items = Item.all + hide_retired + # raise + end + + end + + def show + @item = Item.find_by_id(params[:id]) + if !@item + render_404 + end + end + + def new + @item = Item.new + end + + def create + @item = Item.new item_params + @item.merchant_id = current_merchant.id + @item.category_ids = params[:item][:category_ids] + if @item.save + # @item.merchant_id == nil + redirect_to items_path, flash: {success: "Item added successfully"} + else + flash.now[:error] = "Error has occured" + render "new" + end + end + + def edit + @item=Item.find_by(id: params[:id]) + if @item.nil? + head :not_found + else + params[:category] = @item.categories + end + end + + def update + @item = Item.find_by(id: params[:id]) + + @item.name = item_params[:name] + @item.category_ids = params[:item][:category_ids] + # raise + if @item.update(item_params) + + redirect_to item_path(@item.id) + else + render "edit" + end + end + + def retire + @item = Item.find_by(id: params[:id]) + @item.inventory = nil + if @item.save + flash[:success] = "Item Succesfully Retired" + redirect_to items_path + end + end + + def destroy + if Item.destroy(params[:id]) + flash[:success] = "Item Succesfully Deleted" + redirect_to items_path + else + flash[:success] = "Unable to Delete " + redirect_to items_path + end + end + + def add_to_cart + # if OrderItem.find(params[:id]) + # item = Item.find_by(id: params[:id] + + if existing_order_item && sufficient_inventory + increase_quantity + flash[:notice] = "Added to cart!" + redirect_to :back + elsif existing_order_item && !sufficient_inventory + flash[:notice] = "Not enough in stock!" + redirect_to :back + elsif !existing_order_item && !sufficient_inventory + flash[:notice] = "Not enough in stock!" + redirect_to :back + else + + # raise + if OrderItem.create(order_id: Order.last.id, merchant_id: Item.find(params[:id]).merchant_id, item_id: params[:id], quantity: 1 ) + flash[:notice] = "Added to Cart!" + redirect_to :back + else + flash[:notice] = "something went wrong" + redirect_to items_path + end + end + end + + + def remove_from_cart + # OrderItem.destroy(params[:id]) + order_item = OrderItem.find(params[:id]) + order_item.destroy + flash[:notice] = "Item Deleted" + redirect_to cart_path + end + + def show_cart + @order = Order.where(session_id: session[:id]) + @order_items = OrderItem.where(order_id: @order.last.id) + end + + def update_cart + order_item = OrderItem.find(params[:id]) + if order_item.item.inventory >= params[:order_item][:quantity].to_i + order_item.quantity = params[:order_item][:quantity].to_i + if order_item.save + flash[:success] = "Quantity Updated" + redirect_to cart_path + end + else + flash[:notice] = "Stock too Low!" + redirect_to cart_path + end + end + + private + + def item_params + params.require(:item).permit(:name, :description, :price, :inventory, :merchant_id, :category_ids, :photo) + end + + def find_item + @item = Item.find_by_id(params[:id]) + end + + # #added by AE + # def has_cart + # if OrderItem.where(order_id: Order.where(session_id: session[:user_id])) + # if Order.Where(status: "pending") + # end + # end + # end + + def find_user + if session[:merchant_id] + @login_user = User.find_by(id: session[:user_id]) + end + end + + def find_categories + @categories = Category.all + @categories_names = [] + @categories.each do |category| + @categories_names << category.name + end + # raise + return @categories_names + end + + def sufficient_inventory + if @oi.length > 0 + item = Item.find(@oi.last.item_id) + if item.inventory > 0 + # raise + if @oi.last.quantity < item.inventory + return true + else + return false + end + end + else + return true + end + end + + def existing_order_item + order = Order.find_by(session_id: session[:id]) + @oi = OrderItem.where(item_id: params[:id], order_id: order.id) + if @oi.length > 0 + return true + else + return false + end + end + + def increase_quantity + @oi.last.quantity += 1 + @oi.last.save + end + + def order_params + params.require(:order).permit(:session_id, :status, :total) + end + + def hide_retired + @items = @items.where.not(inventory: nil) + return @items + end +end diff --git a/app/controllers/merchants_controller.rb b/app/controllers/merchants_controller.rb new file mode 100644 index 0000000000..f1da09ae90 --- /dev/null +++ b/app/controllers/merchants_controller.rb @@ -0,0 +1,64 @@ +class MerchantsController < ApplicationController +skip_before_action :require_login, only: [:index, :new, :create, :merchant_items] +# before_action :find_book, only: [:show, :order_by_status] + + def index + @merchants = Merchant.all + end + + def new + @merchant = Merchant.new + end + + def create + # @merchant = Merchant.new(merchant_params) + # if @merchant.save + # flash[:success] = "Successfuly created new Merchant" + # redirect_to merchants_path + # else + # flash.now[:error] = "Merchant could not be created" + # @merchant.errors.messages + # render 'new' + # end + end + + def show + find_merchant + # @merchant = Merchant.find_by_id(params[:id]) + if !@merchant + render_404 #find me in ApplicationController + end + end + + def merchant_items + @items = Item.where(merchant_id: params[:id]) + render "/items/index" + end + + def order_by_status + find_merchant + # @merchant = Merchant.find_by_id(params[:id]) + # @merchant.orders_by_status.where(status: params[:status]) + render '_order_by_status' + #raise + end + + def ship + find_merchant + order_item = @merchant.order_items.find_by(id: params[:order_item]) + #raise + order_item.status = "shipped" + order_item.save + render "show" + end + + private + + # def merchant_params + # params.require(:merchant).permit(:username, :email, :uid, :provider) + # end + + def find_merchant + @merchant = Merchant.find_by_id(params[:id]) + end +end diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb new file mode 100644 index 0000000000..deecd12e8d --- /dev/null +++ b/app/controllers/orders_controller.rb @@ -0,0 +1,90 @@ +class OrdersController < ApplicationController + + skip_before_action :require_login, only: [:pay, :paid, :create] + + def index + @orders = Order.all + end + + def show + current_merchant + @result_order = Order.find(params[:id]) + @payment = Payment.where(order_id: params[:id]).first + end + + def create + @order = Order.create order_params + puts "error: #{@order.errors.messages}" + if @order.id != nil + flash[:success] = "Order added successfully!" + redirect_to orders_path + else + flash.now[:error] = "Error has occured!" + render "edit" + end + end + + # def edit + # @order = Order.find(params[:id]) + # end + + def update + @order = Order.find_by_id(params[:id]) + @order.status = order_params[:status] + if @order.save + redirect_to order_path + else + flash.now[:error] = "Error has occured!" + render "edit" + end + end + + def destroy + Order.destroy(params[:id]) + redirect_to orders_path + end + + def new + @order = Order.new + end + + def pay + @payment = Payment.new + @order = Order.find(params[:id]) + render "pay_form" + end + + def paid + # The default column for payment is id, but id in this methods context is + # an order_id, so we need to reassign it, so it stores the order_id in the correct column name. + actual_params = payment_params + actual_params[:order_id] = params[:id] + @payment = Payment.create actual_params + + if @payment.id != nil + flash[:success] = "Payment successful!" + order_id = params[:id] # to clarify that this is an order ID, not payment ID + @order = Order.find(params[:id]) + + Order.change_status_to_paid(params[:id]) + @order.inventory_adjust + session[:id] = nil + redirect_to confirmation_path(order_id) + else + flash.now[:error] = "Error has occured!" + @order = Order.find(params[:id]) + render "pay_form" + end + end + + private + + def order_params + params.require(:order).permit(:session_id, :status, :total) + end + + def payment_params + params.require(:payment).permit(:name_on_card, :email, :phone_num, :ship_address, :bill_address, :card_number, :expiration_date, :CCV, :order_id ) + end + +end diff --git a/app/controllers/payments_controller.rb b/app/controllers/payments_controller.rb new file mode 100644 index 0000000000..6457ae3455 --- /dev/null +++ b/app/controllers/payments_controller.rb @@ -0,0 +1,11 @@ +class PaymentsController < ApplicationController + skip_before_action :require_login, only: [:confirmation, :new] + + def confirmation + @order = Order.find_by_id(params[:id]) + @order_items = OrderItem.where(:order_id => @order.id) + item_ids = @order_items.map { |i| i.item_id }.uniq + @items = Item.find(item_ids) + end + +end diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb new file mode 100644 index 0000000000..72458fbcc9 --- /dev/null +++ b/app/controllers/reviews_controller.rb @@ -0,0 +1,29 @@ +class ReviewsController < ApplicationController + skip_before_action :require_login + + def new + @review = Review.new + @review.item_id = params[:item_id] + end + + def create + @review = Review.new + @review.item_id = params[:review][:item_id] + @review.rating = params[:review][:rating] + @review.description = params[:review][:description] + @review.save + if @review.id != nil + # flash is working - ks + flash[:success] = "Review added successfully" + redirect_to item_path(params[:id]) + else + flash.now[:error] = "Please select a rating." + render :new + end + end + + # private + # def review_params + # params.permit(:rating, :description, :item_id) + # end +end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb new file mode 100644 index 0000000000..eb6f44dd5f --- /dev/null +++ b/app/controllers/sessions_controller.rb @@ -0,0 +1,47 @@ +class SessionsController < ApplicationController + + skip_before_action :require_login, only: [:create] + #skip_before_action :require_login, only: [:login_form, :login] + + # def login_form; end + + def create + auth_hash = request.env['omniauth.auth'] + + merchant = Merchant.find_by(uid: auth_hash["uid"], provider: auth_hash["provider"]) + + if merchant.nil? + merchant = Merchant.create_from_github(auth_hash) + if merchant.nil? + flash[:error] = "Could not log in." + else + session[:merchant_id] = merchant.id + flash[:success] = "Logged in successfully!" + end + else + session[:merchant_id] = merchant.id + flash[:success] = "Logged in successfully!" + end + redirect_to root_path + end + + # def login + # merchant = Merchant.find_by_username(params[:username]) + # if merchant + # session[:merchant_id] = merchant.id + # flash[:success] = "Welcome back #{ merchant.username }" + # redirect_to items_path + # else + # flash.now[:error] = "Merchant not found" + # render :login_form + # end + # end + + + def logout + session[:merchant_id] = nil + flash[:success] = "You have successfully loged out" + redirect_to root_path + end + +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 0000000000..de6be7945c --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,2 @@ +module ApplicationHelper +end diff --git a/app/helpers/categories_helper.rb b/app/helpers/categories_helper.rb new file mode 100644 index 0000000000..e06f31554c --- /dev/null +++ b/app/helpers/categories_helper.rb @@ -0,0 +1,2 @@ +module CategoriesHelper +end diff --git a/app/helpers/items_helper.rb b/app/helpers/items_helper.rb new file mode 100644 index 0000000000..cff0c9fe21 --- /dev/null +++ b/app/helpers/items_helper.rb @@ -0,0 +1,2 @@ +module ItemsHelper +end diff --git a/app/helpers/merchants_helper.rb b/app/helpers/merchants_helper.rb new file mode 100644 index 0000000000..5337747b0f --- /dev/null +++ b/app/helpers/merchants_helper.rb @@ -0,0 +1,2 @@ +module MerchantsHelper +end diff --git a/app/helpers/orders_helper.rb b/app/helpers/orders_helper.rb new file mode 100644 index 0000000000..443227fd48 --- /dev/null +++ b/app/helpers/orders_helper.rb @@ -0,0 +1,2 @@ +module OrdersHelper +end diff --git a/app/helpers/payments_helper.rb b/app/helpers/payments_helper.rb new file mode 100644 index 0000000000..c1b884f80f --- /dev/null +++ b/app/helpers/payments_helper.rb @@ -0,0 +1,2 @@ +module PaymentsHelper +end diff --git a/app/helpers/reviews_helper.rb b/app/helpers/reviews_helper.rb new file mode 100644 index 0000000000..682b7b1abc --- /dev/null +++ b/app/helpers/reviews_helper.rb @@ -0,0 +1,2 @@ +module ReviewsHelper +end diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb new file mode 100644 index 0000000000..309f8b2eb3 --- /dev/null +++ b/app/helpers/sessions_helper.rb @@ -0,0 +1,2 @@ +module SessionsHelper +end diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000000..a009ace51c --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb new file mode 100644 index 0000000000..286b2239d1 --- /dev/null +++ b/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: 'from@example.com' + layout 'mailer' +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000000..10a4cba84d --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end diff --git a/app/models/category.rb b/app/models/category.rb new file mode 100644 index 0000000000..fb3136d69c --- /dev/null +++ b/app/models/category.rb @@ -0,0 +1,4 @@ +class Category < ApplicationRecord + has_and_belongs_to_many :items + validates :name, presence: true, uniqueness: true +end diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/models/item.rb b/app/models/item.rb new file mode 100644 index 0000000000..c0f20e240c --- /dev/null +++ b/app/models/item.rb @@ -0,0 +1,33 @@ +class Item < ApplicationRecord + belongs_to :merchant + has_and_belongs_to_many :categories + has_many :order_items + has_many :reviews, dependent: :destroy + + + validates :price, presence: true, numericality: { greater_than: 0 } + validates :inventory, presence: true, numericality: { only_integer: true, greater_than: -1 }, :allow_nil => true + validates :name, presence: true, uniqueness: true + validates :photo, presence: true + + + def average_rating + total = 0 + num_of_ratings = 0 + self.reviews.each do |review| + if review.rating != nil + total += review.rating + num_of_ratings += 1 + end + end + if num_of_ratings > 0 + return (total/num_of_ratings.to_f).round(1) + else + return "no rating yet" + end + end + + + + +end diff --git a/app/models/merchant.rb b/app/models/merchant.rb new file mode 100644 index 0000000000..08516b978a --- /dev/null +++ b/app/models/merchant.rb @@ -0,0 +1,92 @@ +class Merchant < ApplicationRecord + validates :username, presence: true, uniqueness: true + validates :email, presence: true, uniqueness: true + has_many :items + has_many :order_items + accepts_nested_attributes_for :items + + + def self.create_from_github(auth_hash) + merchant = Merchant.new + + if auth_hash["uid"] == nil || auth_hash["provider"] == nil || auth_hash["info"] == nil + return nil + end + + merchant.uid = auth_hash["uid"] + merchant.provider = auth_hash["provider"] + merchant.username = auth_hash["info"]["nickname"] + merchant.email = auth_hash["info"]["email"] + + merchant.save ? merchant : nil + + end + + + def merchant_orders + # TODO Self.orders? + orders = order_items.map { |order_item| order_item.order } + return orders.uniq + end + + def items_by_order(order_id) + # TODO order_id.order_items? + items = order_items.where(order_id: order_id) + return items + end + + + def revenue + total_revenue = 0 + orders_by_status('paid').each {|order| total_revenue += revenue_by_order(order)} + orders_by_status('complete').each {|order| total_revenue += revenue_by_order(order)} + return total_revenue.round(2) + end + + def revenue_by_status(status) + # TODO returns float + total = 0 + orders_by_status(status).map do |order| + total += revenue_by_order(order) + end + return total.round(2) + end + + def revenue_by_order(order) + # TODO returns float + total = 0 + items_by_order(order).map {|order_item| total += subtotal(order_item)} + return total.round(2) + end + + + def order_status + status = %w(pending paid complete canceled) + return status + end + + def orders_by_status(status) + #TODO # retuns order objects + orders = merchant_orders.select do |order| + order.status == status + end + return orders + end + + # def items_by_status(status) + # # TODO returns order_item objects + # items = order_items.where(status: status) + # return items + # end + + def total_orders_by_status(status) + # TODO # returns an integer + return orders_by_status(status).length + end + + + def subtotal(order_item) + return order_item.item.price * order_item.quantity + end + +end diff --git a/app/models/order.rb b/app/models/order.rb new file mode 100644 index 0000000000..2920e683a5 --- /dev/null +++ b/app/models/order.rb @@ -0,0 +1,37 @@ +class Order < ApplicationRecord + has_many :order_items + + validates :status, presence: true, inclusion: { in: %w(pending paid complete cancelled), message: "%{value} is not a valid status" } + validates :session_id, presence: true + # validates :total, presence: true, numericality: { only_float: true, greater_than: -1 } + + def total_cost + + total = 0.0 + + self.order_items.each do | order_item | + item = Item.find_by_id(order_item.item_id) + total += (item.price * order_item.quantity) + end + return total.round(2) + end + + def self.change_status_to_paid(order_id) + order = Order.find_by_id(order_id) + order.status = "paid" + order.save + + end + + def inventory_adjust + + self.order_items.each do | order_item | + item = Item.find_by_id(order_item.item_id) + if order_item.quantity <= item.inventory + item.inventory -= order_item.quantity # reduce that items inventory by the quantity bought + puts item.merchant_id + item.save + end + end + end +end diff --git a/app/models/order_item.rb b/app/models/order_item.rb new file mode 100644 index 0000000000..ea259d0288 --- /dev/null +++ b/app/models/order_item.rb @@ -0,0 +1,7 @@ +class OrderItem < ApplicationRecord + belongs_to :item + belongs_to :order + + validates :quantity, presence: true, numericality: { only_integer: true, greater_than: 0 } + +end diff --git a/app/models/payment.rb b/app/models/payment.rb new file mode 100644 index 0000000000..154d34f401 --- /dev/null +++ b/app/models/payment.rb @@ -0,0 +1,19 @@ +class Payment < ApplicationRecord + belongs_to :order + + validates :name_on_card, presence: true + validates :email, presence: true + validates :phone_num, presence: true + validates :ship_address, presence: true + validates :bill_address, presence: true + validates :card_number, presence: true, numericality: { only_integer: true, greater_than: 0 } + validates_length_of :card_number, :minimum => 16, :maximum => 19 + validates :expiration_date, presence: true + validates_length_of :expiration_date, :minimum => 4, :maximum => 4 + validates :CCV, presence: true + validates_length_of :CCV, :minimum => 3, :maximum => 4 + validates :order_id, presence: true + + def paid + end +end diff --git a/app/models/review.rb b/app/models/review.rb new file mode 100644 index 0000000000..9b65db085d --- /dev/null +++ b/app/models/review.rb @@ -0,0 +1,5 @@ +class Review < ApplicationRecord + belongs_to :item + + validates :rating, presence: true, numericality: { only_integer: true, :greater_than => 0, :less_than_or_equal_to => 5 } +end diff --git a/app/views/categories/new.html.erb b/app/views/categories/new.html.erb new file mode 100644 index 0000000000..ff9de59169 --- /dev/null +++ b/app/views/categories/new.html.erb @@ -0,0 +1,20 @@ +

Create a new category!

+ + + + +<%= form_for @category do |f| %> + + <%= f.label :name %> + <%= f.text_field :name %> + <%= f.submit %> + +<% end %> diff --git a/app/views/items/_form.html.erb b/app/views/items/_form.html.erb new file mode 100644 index 0000000000..8b780b7884 --- /dev/null +++ b/app/views/items/_form.html.erb @@ -0,0 +1,34 @@ +<% if !@item.nil? %> + + +<%= form_for @item do |f| %> + +<%= f.label :name %>
+<%= f.text_field :name %>
+ +<%= f.label :price %>
+<%= f.text_field :price %>
+ +<%= f.label :description %>
+<%= f.text_field :description %>
+ +<%= f.label :Amount_in_Stock %>
+<%= f.text_field :inventory %>
+ +<%= f.label :photo %>
+<%= f.text_field :photo %> + +<%= f.label :categories %>
+<%= f.select :category_ids, options_for_select(@categories.collect { | category | [category.name, category.id] }), { :prompt => "Please select"}, { :multiple => true} %> +<%= f.submit action_name, :class => "button" %> + +<% end %> + + +<%end%> diff --git a/app/views/items/edit.html.erb b/app/views/items/edit.html.erb new file mode 100644 index 0000000000..c02c4c53b9 --- /dev/null +++ b/app/views/items/edit.html.erb @@ -0,0 +1,5 @@ +

Edit <%= @item.name %>

+ +
+ <%= render partial: "form", locals: { action_name: "Update Item", form_method: :put}%> +
diff --git a/app/views/items/index.html.erb b/app/views/items/index.html.erb new file mode 100644 index 0000000000..265e0fc90c --- /dev/null +++ b/app/views/items/index.html.erb @@ -0,0 +1,30 @@ +<% if @items.count > 0 %> + +
+<% @items.sort.each do |item| %> +
+
+

<%=link_to "#{item.name.capitalize}", item_path(item.id), method: :get%>

+ <%= link_to image_tag(item.photo, :size => "200x300", :alt => "item photo #{item.name}"), item_path(item.id) %> +
Average Rating: <%= "#{item.average_rating}" %>
+
Price: $<%= "#{item.price}"%>
+ <% if !session[:merchant_id] %> +
<%= link_to "Add to Cart", add_to_cart_path(item.id), method: :patch%>
+ <% end %> + <% if session[:merchant_id] %> + <%= link_to "⚙️", edit_item_path(item.id), method: :get %> + <%= link_to "🔒", retire_path(item.id), method: :patch %> + <% end %> +
+
+<% end %> +
+<% else %> +

+<%= "Coming Soon!" %> +

+<% end %> + +<% if session[:merchant_id] %> +<%= link_to "Add New Item", new_item_path, method: :get %> +<% end %> diff --git a/app/views/items/new.html.erb b/app/views/items/new.html.erb new file mode 100644 index 0000000000..f8e114d437 --- /dev/null +++ b/app/views/items/new.html.erb @@ -0,0 +1,6 @@ +Add new Item + + +
+ <%= render partial: "form", locals: { action_name: "Add item", form_method: :post }%> +
diff --git a/app/views/items/root.html.erb b/app/views/items/root.html.erb new file mode 100644 index 0000000000..250d8896fa --- /dev/null +++ b/app/views/items/root.html.erb @@ -0,0 +1,12 @@ +

Package of the day!

+ +
+<% @featured_items.each do |item| %> +
+
+

<%= link_to item.name, item_path(item.id) %>

+ <%= link_to image_tag(item.photo, :size => "200x300", :alt => "item photo #{item.name}"), item_path(item.id) %> +
+
+<% end %> +
diff --git a/app/views/items/show.html.erb b/app/views/items/show.html.erb new file mode 100644 index 0000000000..76d092e002 --- /dev/null +++ b/app/views/items/show.html.erb @@ -0,0 +1,76 @@ +

<%= @item.name %>

+ +
+ +

+ <% unless @item.photo == nil %> + <%= image_tag(@item.photo, :size => "300x400", :alt => "item photo") %> + <% end %> +

+ +

Description

+

+ <%= @item.description %> +

+

+ $<%= @item.price%> +

+ + +
+ + +
+ + <% if !session[:merchant_id] %> + + + + + + <% end %> + <% if session[:merchant_id] %> + + + <% end %> +
+ + +
+

Reviews

+ <% if @item.reviews.length > 0 %> + <% @item.reviews.each do |review| %> +
+

+ Rating: + <% if review.rating == 1 %> + <%= "💛♡♡♡♡" %> + <% elsif review.rating == 2 %> + <%= "💛💛♡♡♡" %> + <% elsif review.rating == 3 %> + <%= "💛💛💛♡♡" %> + <% elsif review.rating == 4 %> + <%= "💛💛💛💛♡" %> + <% else %> + <%= "💛💛💛💛💛" %> + <% end %> +

+

<%= "#{review.description}" %>

+
+ <% end %> + <% else %> +

Sorry, no reviews

+ <% end %> +
diff --git a/app/views/items/show_cart.html.erb b/app/views/items/show_cart.html.erb new file mode 100644 index 0000000000..5e396ef6dd --- /dev/null +++ b/app/views/items/show_cart.html.erb @@ -0,0 +1,54 @@ + +<% if @order_items.length != 0 %> + + + + + +

Items in your cart:

+ + + + + + + + + + <% @order_items.sort.each do |oi| %> + + + + + <% end %> + + + + <% end %> + + <% else %> + Is Empty + <% end %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb new file mode 100644 index 0000000000..d4d55ad589 --- /dev/null +++ b/app/views/layouts/application.html.erb @@ -0,0 +1,121 @@ + + +
+ + + + <%= favicon_link_tag %> + + + + + Betsy + <%= stylesheet_link_tag "application" %> + <%= javascript_include_tag "application", 'data-turbolinks-track' => true %> + <%= csrf_meta_tags %> + + + +
+ + +
+

<%= link_to "Besty", root_path %>

+
+ <% if session[:merchant_id] == nil %> +

<%= @cart_quantity %>

+ + <% end %> +
+
+ + +<% flash.each do |name, message| %> +

<%= message %>

+<% end %> +
+ + + + <%= yield %> + + + + +
+
+ diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000000..cbd34d2e9d --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000000..37f0bddbd7 --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/app/views/merchants/_merchant_orders.html.erb b/app/views/merchants/_merchant_orders.html.erb new file mode 100644 index 0000000000..0f551b3913 --- /dev/null +++ b/app/views/merchants/_merchant_orders.html.erb @@ -0,0 +1,25 @@ +
+ +

Merchant Orders

+ +
+ Item + + Price + + Quantity + + + + +
+ <%= oi.item.name %> + + <%= oi.item.price %> + + <%= form_for oi do | order_form | %> + <%= order_form.number_field :quantity, min: 1, max: oi.item.inventory %> + + <%= order_form.submit %> + + <%= link_to "Remove", remove_from_cart_path(oi.id), { data: { confirm: "Are you sure you wish to delete the product '#{oi.item.name}' from your cart?" }, method: :delete } %> +
+ + + + + <% @merchant.merchant_orders.each do |order| %> + + + + <%end%> + +
+ Order Id + + order total +
+ <%=link_to "#{order.id}", order_path(order.id), method: :get%> + + $<%= sprintf('%.2f', @merchant.revenue_by_order(order))%> +
+ diff --git a/app/views/merchants/_order_by_status.html.erb b/app/views/merchants/_order_by_status.html.erb new file mode 100644 index 0000000000..8bce28713c --- /dev/null +++ b/app/views/merchants/_order_by_status.html.erb @@ -0,0 +1,41 @@ +
+ +

Your <%= params[:status] %> Orders

+ + + + + + + + <% @merchant.orders_by_status(params[:status]).each do |order| %> + + <%# raise %> + + + + <%end%> + +
+ + + Order Id + + order total +
+ <%= order.status%> + + <%=link_to "#{order.id}", order_path(order.id), method: :get%> + + $<%= sprintf('%.2f', @merchant.revenue_by_order(order))%> +
+
+ +<%= link_to "Back", merchant_path(@merchant) %> diff --git a/app/views/merchants/_order_items.html.erb b/app/views/merchants/_order_items.html.erb new file mode 100644 index 0000000000..a3039ccd4a --- /dev/null +++ b/app/views/merchants/_order_items.html.erb @@ -0,0 +1,66 @@ +
+

Order Items

+ + + + + + + + + + + + +<% @merchant.order_items.each do |order_item| %> + + + + + + + + + + + <%end%> + +
+ Item + + Subtotal + + Quantity + + Order ID + + Status + + Date + + Time + + Shipped +
+ <%=link_to "#{Item.find(order_item.item_id).name.capitalize}", item_path(order_item.item_id), method: :get%> + + $<%= sprintf('%.2f', @merchant.subtotal(order_item) )%> + + <%= order_item.quantity%> + + <%= link_to order_item.order_id, order_path(order_item.order_id) %> + + <%= order_item.order.status %> + + <%= order_item.updated_at.strftime('%v') %> + + <%= order_item.updated_at.strftime('%r') %> + + <% if order_item.status.nil? %> + <%= link_to 'ship', ship_order_path(order_item: order_item.id), method: :put %> + <% else %> + <%= "✔︎" %> + <% end %> +
+ +
diff --git a/app/views/merchants/_totals_by_status.html.erb b/app/views/merchants/_totals_by_status.html.erb new file mode 100644 index 0000000000..ca0f869419 --- /dev/null +++ b/app/views/merchants/_totals_by_status.html.erb @@ -0,0 +1,70 @@ +

Totals by Status

+ + + + + + + + + + + <%# raise %> + + + + + + + + + + + + + + + + + + + + +
+ + + Orders + + Revenue +
+ Pending + + <%= @merchant.total_orders_by_status("pending") %> + + $<%= @merchant.revenue_by_status("pending") %> +
+ Paid + + <%= @merchant.total_orders_by_status("paid") %> + + $<%= @merchant.revenue_by_status("paid") %> +
+ Complete + + <%= @merchant.total_orders_by_status("complete") %> + + $<%= @merchant.revenue_by_status("complete") %> +
+ Canceled + + <%= @merchant.total_orders_by_status("canceled") %> + + $<%= @merchant.revenue_by_status("canceled") %> +
diff --git a/app/views/merchants/index.html.erb b/app/views/merchants/index.html.erb new file mode 100644 index 0000000000..16a18b3825 --- /dev/null +++ b/app/views/merchants/index.html.erb @@ -0,0 +1,9 @@ + + + diff --git a/app/views/merchants/new.html.erb b/app/views/merchants/new.html.erb new file mode 100644 index 0000000000..71ae768576 --- /dev/null +++ b/app/views/merchants/new.html.erb @@ -0,0 +1,27 @@ +

Merchants#new

+

Find me in app/views/merchants/new.html.erb

+ + + +
+ +<%= form_for @merchant do |f| %> + + <%= f.label :username %> + <%= f.text_field :username %> + <%= f.label :email %> + <%= f.text_field :email %> + + <%= f.submit %> + +<% end %> + +
diff --git a/app/views/merchants/show.html.erb b/app/views/merchants/show.html.erb new file mode 100644 index 0000000000..c3c1db738f --- /dev/null +++ b/app/views/merchants/show.html.erb @@ -0,0 +1,15 @@ +

<%= @merchant.username %> Order Fulfillment

+ +
+

Total Revenue:

+ $<%= sprintf('%.2f', @merchant.revenue) %> +
+ +<%= render partial: "totals_by_status" %> + +<%= render partial: "merchant_orders" %> + +<%= render partial: "order_items" %> + + + diff --git a/app/views/orders/_form.html.erb b/app/views/orders/_form.html.erb new file mode 100644 index 0000000000..cd62d106f6 --- /dev/null +++ b/app/views/orders/_form.html.erb @@ -0,0 +1,29 @@ + + + + +<%= form_for @order, method: form_method do |f| %> + + Order id:<%= @order.id %> + + <%= f.label :status %> + <%= f.text_field :status %> + + <%= f.label :total %> + <%= f.text_field :total, :disabled => true %> + + <%= f.submit action_name %> + +<% end %> + + diff --git a/app/views/orders/_order_items.html.erb b/app/views/orders/_order_items.html.erb new file mode 100644 index 0000000000..f8bd0157aa --- /dev/null +++ b/app/views/orders/_order_items.html.erb @@ -0,0 +1,66 @@ +
+

Order Items

+ + + + + + + + + + + + +<% @login_merchant.items_by_order(@result_order.id).each do |order_item| %> + + + + + + + + + + + <%end%> + +
+ Item + + Subtotal + + Quantity + + Order ID + + Status + + Date + + Time + + Shipped +
+ <%=link_to "#{Item.find(order_item.item_id).name.capitalize}", item_path(order_item.item_id), method: :get%> + + $<%= sprintf('%.2f', @login_merchant.subtotal(order_item) )%> + + <%= order_item.quantity%> + + <%= link_to order_item.order_id, order_path(order_item.order_id) %> + + <%= order_item.order.status %> + + <%= order_item.updated_at.strftime('%v') %> + + <%= order_item.updated_at.strftime('%r') %> + + <% if order_item.status.nil? %> + <%= link_to 'ship', ship_order_path(order_item: order_item.id), method: :put %> + <% else %> + <%= "✔︎" %> + <% end %> +
+ +
diff --git a/app/views/orders/create.html.erb b/app/views/orders/create.html.erb new file mode 100644 index 0000000000..675a76c4b9 --- /dev/null +++ b/app/views/orders/create.html.erb @@ -0,0 +1,5 @@ +

Create an order

+
+ +<%= render partial: "form", locals: { action_name: "Create", form_method: :put } %> +
diff --git a/app/views/orders/edit.html.erb b/app/views/orders/edit.html.erb new file mode 100644 index 0000000000..3b67e2c551 --- /dev/null +++ b/app/views/orders/edit.html.erb @@ -0,0 +1,4 @@ +

Update an order

+
+ <%= render partial: "form", locals: { action_name: "Update", form_method: :put } %> +
diff --git a/app/views/orders/index.html.erb b/app/views/orders/index.html.erb new file mode 100644 index 0000000000..f2d0231c35 --- /dev/null +++ b/app/views/orders/index.html.erb @@ -0,0 +1,15 @@ + +

Order List

+ +

+ + +

diff --git a/app/views/orders/pay_form.html.erb b/app/views/orders/pay_form.html.erb new file mode 100644 index 0000000000..bb7f5c6eac --- /dev/null +++ b/app/views/orders/pay_form.html.erb @@ -0,0 +1,45 @@ + + + + +<%= form_for @payment, method: :post, url: paid_path(@order.id) do |f| %> + + <%= f.label :name_on_card %> + <%= f.text_field :name_on_card, :placeholder => "Name as it appears on card" %> + + <%= f.label :email %> + <%= f.text_field :email, :placeholder => "Email address" %> + + <%= f.label :phone_num %> + <%= f.text_field :phone_num, :placeholder => "Phone number"%> + + <%= f.label :ship_address %> + <%= f.text_field :ship_address, :placeholder => "Shipping address" %> + + <%= f.label :bill_address %> + <%= f.text_field :bill_address, :placeholder => "Billing address" %> + + <%= f.label :card_number %> + <%= f.text_field :card_number, :placeholder => "Credit card number" %> + + <%= f.label :expiration_date %> + <%= f.text_field :expiration_date, :placeholder => "****"%> + + <%= f.label :CCV %> + <%= f.text_field :CCV, :placeholder => "3 or 4 digit number" %> + + <%= f.submit "Pay" %> + +<% end %> + + diff --git a/app/views/orders/show.html.erb b/app/views/orders/show.html.erb new file mode 100644 index 0000000000..cc7ecdadc8 --- /dev/null +++ b/app/views/orders/show.html.erb @@ -0,0 +1,50 @@ +

Selected order

+ +

+ +

+ +
+ +
+ +<%= render partial: "order_items" %> + +
+ <% if @payment != nil %> + + <% end %> +
+ + + + + + diff --git a/app/views/payments/confirmation.html.erb b/app/views/payments/confirmation.html.erb new file mode 100644 index 0000000000..ca9d1ad3f3 --- /dev/null +++ b/app/views/payments/confirmation.html.erb @@ -0,0 +1,22 @@ + +

Order Confirmation

+ +

+

Order placed: <%= @order.created_at.to_date %>

+

Order total: $<%= @order.total_cost.round(2) %>

+

+
+

Order status: <%= @order.status %>

+

Order id: <%= @order.id %>

+
+ +

+ <% @items.each do | item | %> + +

<%=item.photo%>

+

<%=link_to item.description, item_path(item.id)%>

+

<%=quant = @order_items.where(item_id: item.id).map { |i| i.quantity }.sum%>

+

Price: $<%=item.price.round(2) * quant%>

+ <% end %> + +

diff --git a/app/views/payments/new.html.erb b/app/views/payments/new.html.erb new file mode 100644 index 0000000000..b2f31c25e5 --- /dev/null +++ b/app/views/payments/new.html.erb @@ -0,0 +1 @@ +<%= render partial: "/orders/pay_form", locals: { action_name: "New", form_method: :post } %> diff --git a/app/views/reviews/_form.html.erb b/app/views/reviews/_form.html.erb new file mode 100644 index 0000000000..39db961445 --- /dev/null +++ b/app/views/reviews/_form.html.erb @@ -0,0 +1,37 @@ +
+
+ +
    + <% @review.errors.each do + |field, msg| %> +
  • + <%= field %> <%= msg %> +
  • + <% end %> +
+ + <%= form_for @review, method: form_method, url: item_path(@review.item_id) do |f| %> + + <%= f.radio_button(:rating, 1) %> + <%= f.label :rating, "💛♡♡♡♡" %> + <%= f.radio_button(:rating, 2) %> + <%= f.label :rating, "💛💛♡♡♡" %> + <%= f.radio_button(:rating, 3) %> + <%= f.label :rating, "💛💛💛♡♡" %> + <%= f.radio_button(:rating, 4) %> + <%= f.label :rating, "💛💛💛💛♡" %> + <%= f.radio_button(:rating, 5) %> + <%= f.label :rating, "💛💛💛💛💛" %> + + <%= f.label :description %> + <%= f.text_area :description %> + + <%= f.hidden_field :item_id, value: @review.item_id %> + + <%= f.submit action_name, :class => "button" %> + + <% end %> + +
+ +
diff --git a/app/views/reviews/new.html.erb b/app/views/reviews/new.html.erb new file mode 100644 index 0000000000..ff5cff3c43 --- /dev/null +++ b/app/views/reviews/new.html.erb @@ -0,0 +1,4 @@ +

New Review for

+

Review <%= Item.find(@review.item_id).name %>

+ +<%= render partial: "form", locals: { action_name: "Add Review", form_method: :post }%> 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..fd0e86d643 --- /dev/null +++ b/bin/rails @@ -0,0 +1,15 @@ +#!/usr/bin/env ruby +if ENV['RAILS_ENV'] == 'test' + require 'simplecov' + SimpleCov.start 'rails' + puts "required simplecov" +end + +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..e620b4dadb --- /dev/null +++ b/bin/setup @@ -0,0 +1,34 @@ +#!/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') + + # 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/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..108ca7e505 --- /dev/null +++ b/config/application.rb @@ -0,0 +1,19 @@ +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 + # Force new test files to be generated in the minitest-spec style + config.generators do |g| + g.test_framework :minitest, spec: true + end + # 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..0bbde6f74f --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,9 @@ +development: + adapter: async + +test: + adapter: async + +production: + adapter: redis + url: redis://localhost:6379/1 diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000000..87c99d6349 --- /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..6f7197045a --- /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=172800' + } + 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..1d71624632 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,86 @@ +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 + + # 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..30587ef6d5 --- /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=3600' + } + + # 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..51639b67a0 --- /dev/null +++ b/config/initializers/application_controller_renderer.rb @@ -0,0 +1,6 @@ +# Be sure to restart your server when you modify this file. + +# ApplicationController.renderer.defaults.merge!( +# http_host: 'example.org', +# https: false +# ) diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb new file mode 100644 index 0000000000..01ef3e6630 --- /dev/null +++ b/config/initializers/assets.rb @@ -0,0 +1,11 @@ +# 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 + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in app/assets folder are already added. +# Rails.application.config.assets.precompile += %w( search.js ) 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/new_framework_defaults.rb b/config/initializers/new_framework_defaults.rb new file mode 100644 index 0000000000..671abb69a3 --- /dev/null +++ b/config/initializers/new_framework_defaults.rb @@ -0,0 +1,24 @@ +# Be sure to restart your server when you modify this file. +# +# This file contains migration options to ease your Rails 5.0 upgrade. +# +# Read the Guide for Upgrading Ruby on Rails for more info on each option. + +# Enable per-form CSRF tokens. Previous versions had false. +Rails.application.config.action_controller.per_form_csrf_tokens = true + +# Enable origin-checking CSRF mitigation. Previous versions had false. +Rails.application.config.action_controller.forgery_protection_origin_check = true + +# Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`. +# Previous versions had false. +ActiveSupport.to_time_preserves_timezone = true + +# Require `belongs_to` associations by default. Previous versions had false. +Rails.application.config.active_record.belongs_to_required_by_default = true + +# Do not halt callback chains when a callback returns false. Previous versions had true. +ActiveSupport.halt_callback_chains_on_return_false = false + +# Configure SSL options to enable HSTS with subdomains. Previous versions had false. +Rails.application.config.ssl_options = { hsts: { subdomains: true } } 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/session_store.rb b/config/initializers/session_store.rb new file mode 100644 index 0000000000..8d7200dd07 --- /dev/null +++ b/config/initializers/session_store.rb @@ -0,0 +1,3 @@ +# Be sure to restart your server when you modify this file. + +Rails.application.config.session_store :cookie_store, key: '_betsy_session' 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..0653957166 --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,23 @@ +# 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. +# +# 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..c7f311f811 --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,47 @@ +# 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 }.to_i +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! + +# 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 `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, 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..185c120c92 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,46 @@ +Rails.application.routes.draw do + get 'payments/new' + + root 'items#root' + delete '/item/:id/remove_from_cart', to: 'items#remove_from_cart', as: "remove_from_cart" + patch 'item/:id/retire', to: 'items#retire', as: "retire" + get '/items', to: 'items#index' + get "/items/cart", to: "items#show_cart", as: "cart" + patch '/item/cart/update_cart/:id', to: 'items#update_cart', as: "order_item" + patch '/item/:id/add_to_cart', to: 'items#add_to_cart', as: 'add_to_cart' + # get '/login', to: 'sessions#login_form' + # post '/login', to: 'sessions#login' + delete '/logout', to: 'sessions#logout' + get '/auth/github/callback', to: 'sessions#create' + + get '/merchants', to: 'merchants#index', as: 'merchants' + post '/merchants', to: 'merchants#create' + get '/merchants/new', to: 'merchants#new', as: 'new_merchant' + get '/merchants/:id', to: 'merchants#show', as: 'merchant' + get '/merchants/:id/items', to: 'merchants#merchant_items', as: 'merchant_items' + get '/merchants/:id/:status', to: 'merchants#order_by_status', as: 'order_by_status' + put '/merchants/:id/ship/:order_item', to: 'merchants#ship', as: 'ship_order' + + + + resources :items do + + resources :reviews, except: [:index, :show] + end + + + post "/items/:id", to: "reviews#create" + + + resources :categories, except: [:edit, :update, :destroy, :show] do + get '/items', to: 'items#index' + end + + resources :orders + get '/orders/:id/pay', to: 'orders#pay', as: 'pay' + post '/orders/:id/pay', to: 'orders#paid', as: 'paid' + + get '/payments/:id/confirmation', to: 'payments#confirmation', as: 'confirmation' + + # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html +end diff --git a/config/secrets.yml b/config/secrets.yml new file mode 100644 index 0000000000..77b507e848 --- /dev/null +++ b/config/secrets.yml @@ -0,0 +1,22 @@ +# 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. + +development: + secret_key_base: 29522ab7ae003a8814bda6014bc9242e98a940bf8d89e06c100c3a452f4b6339a16785c04a625387ad6c4ab03dd8527b164532e85826057f5efbf781f79f70aa + +test: + secret_key_base: 9d2d71b2d47898da8adb6f9ccab08ebd532464fb84a6b45bf2cfcc1cddd50fa958982e016b99d78f7e8e9d918d1a377a0c1a260f3b77a07261dc3f481e98ed09 + +# Do not keep production secrets in the repository, +# instead read values from the environment. +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/20170420165739_create_orders.rb b/db/migrate/20170420165739_create_orders.rb new file mode 100644 index 0000000000..03f53bc7d0 --- /dev/null +++ b/db/migrate/20170420165739_create_orders.rb @@ -0,0 +1,11 @@ +class CreateOrders < ActiveRecord::Migration[5.0] + def change + create_table :orders do |t| + t.integer :session_id + t.string :status + t.float :total + + t.timestamps + end + end +end diff --git a/db/migrate/20170420170412_create_order_items.rb b/db/migrate/20170420170412_create_order_items.rb new file mode 100644 index 0000000000..42c5bb30ee --- /dev/null +++ b/db/migrate/20170420170412_create_order_items.rb @@ -0,0 +1,11 @@ +class CreateOrderItems < ActiveRecord::Migration[5.0] + def change + create_table :order_items do |t| + t.integer :item_id + t.integer :order_id + t.integer :quantity + + t.timestamps + end + end +end diff --git a/db/migrate/20170420170947_create_merchants.rb b/db/migrate/20170420170947_create_merchants.rb new file mode 100644 index 0000000000..40783f0da5 --- /dev/null +++ b/db/migrate/20170420170947_create_merchants.rb @@ -0,0 +1,12 @@ +class CreateMerchants < ActiveRecord::Migration[5.0] + def change + create_table :merchants do |t| + t.string :username + t.string :email + t.integer :uid + t.string :provider + + t.timestamps + end + end +end diff --git a/db/migrate/20170420172550_create_reviews.rb b/db/migrate/20170420172550_create_reviews.rb new file mode 100644 index 0000000000..cc304b2742 --- /dev/null +++ b/db/migrate/20170420172550_create_reviews.rb @@ -0,0 +1,12 @@ +class CreateReviews < ActiveRecord::Migration[5.0] + def change + create_table :reviews do |t| + t.integer :merchant_id + t.integer :item_id + t.string :review + t.integer :rating + + t.timestamps + end + end +end diff --git a/db/migrate/20170420193944_create_categories.rb b/db/migrate/20170420193944_create_categories.rb new file mode 100644 index 0000000000..4d7134ae71 --- /dev/null +++ b/db/migrate/20170420193944_create_categories.rb @@ -0,0 +1,9 @@ +class CreateCategories < ActiveRecord::Migration[5.0] + def change + create_table :categories do |t| + t.string :name + + t.timestamps + end + end +end diff --git a/db/migrate/20170420194803_create_items.rb b/db/migrate/20170420194803_create_items.rb new file mode 100644 index 0000000000..344b4998b3 --- /dev/null +++ b/db/migrate/20170420194803_create_items.rb @@ -0,0 +1,14 @@ +class CreateItems < ActiveRecord::Migration[5.0] + def change + create_table :items do |t| + t.integer :merchant_id + t.string :name + t.string :description + t.float :price + t.integer :inventory + t.string :photo + + t.timestamps + end + end +end diff --git a/db/migrate/20170420195242_create_categories_items_join.rb b/db/migrate/20170420195242_create_categories_items_join.rb new file mode 100644 index 0000000000..0b04149349 --- /dev/null +++ b/db/migrate/20170420195242_create_categories_items_join.rb @@ -0,0 +1,10 @@ +class CreateCategoriesItemsJoin < ActiveRecord::Migration[5.0] + def change + create_table :categories_items do |t| + t.belongs_to :category, index: true + t.belongs_to :item, index: true + + t.timestamps + end + end +end diff --git a/db/migrate/20170421230332_remove_column_from_review.rb b/db/migrate/20170421230332_remove_column_from_review.rb new file mode 100644 index 0000000000..295b6c895b --- /dev/null +++ b/db/migrate/20170421230332_remove_column_from_review.rb @@ -0,0 +1,5 @@ +class RemoveColumnFromReview < ActiveRecord::Migration[5.0] + def change + remove_column :reviews, :merchant_id, :string + end +end diff --git a/db/migrate/20170423043927_fix_review_column_name.rb b/db/migrate/20170423043927_fix_review_column_name.rb new file mode 100644 index 0000000000..0d2aeb032b --- /dev/null +++ b/db/migrate/20170423043927_fix_review_column_name.rb @@ -0,0 +1,5 @@ +class FixReviewColumnName < ActiveRecord::Migration[5.0] + def change + rename_column :reviews, :review, :description + end +end diff --git a/db/migrate/20170423045334_remove_reviews_column_add_foregein_key.rb b/db/migrate/20170423045334_remove_reviews_column_add_foregein_key.rb new file mode 100644 index 0000000000..eb546dd5b9 --- /dev/null +++ b/db/migrate/20170423045334_remove_reviews_column_add_foregein_key.rb @@ -0,0 +1,7 @@ +class RemoveReviewsColumnAddForegeinKey < ActiveRecord::Migration[5.0] + def change + remove_column :reviews, :item_id + + add_reference :reviews, :item, index: true, foreign_key: true + end +end diff --git a/db/migrate/20170423174938_create_payments.rb b/db/migrate/20170423174938_create_payments.rb new file mode 100644 index 0000000000..cb40ca0636 --- /dev/null +++ b/db/migrate/20170423174938_create_payments.rb @@ -0,0 +1,16 @@ +class CreatePayments < ActiveRecord::Migration[5.0] + def change + create_table :payments do |t| + t.string :name_on_card + t.string :email + t.string :phone_num + t.string :ship_address + t.string :bill_address + t.string :card_number + t.string :expiration_date + t.string :CCV + + t.timestamps + end + end +end diff --git a/db/migrate/20170424040022_fix_columns_in_merchants.rb b/db/migrate/20170424040022_fix_columns_in_merchants.rb new file mode 100644 index 0000000000..cbef86ea48 --- /dev/null +++ b/db/migrate/20170424040022_fix_columns_in_merchants.rb @@ -0,0 +1,7 @@ +class FixColumnsInMerchants < ActiveRecord::Migration[5.0] + def change + change_column :merchants, :uid, :integer, null: false + change_column :merchants, :provider, :string, null: false + + end +end diff --git a/db/migrate/20170424051818_add_merchant_id_to_order_items.rb b/db/migrate/20170424051818_add_merchant_id_to_order_items.rb new file mode 100644 index 0000000000..2a4f50d99e --- /dev/null +++ b/db/migrate/20170424051818_add_merchant_id_to_order_items.rb @@ -0,0 +1,5 @@ +class AddMerchantIdToOrderItems < ActiveRecord::Migration[5.0] + def change + add_column :order_items, :merchant_id, :integer, index: true, foreign_key: true + end +end diff --git a/db/migrate/20170426012917_add_order_id_to_payment.rb b/db/migrate/20170426012917_add_order_id_to_payment.rb new file mode 100644 index 0000000000..71287242b0 --- /dev/null +++ b/db/migrate/20170426012917_add_order_id_to_payment.rb @@ -0,0 +1,5 @@ +class AddOrderIdToPayment < ActiveRecord::Migration[5.0] + def change + add_column :payments, :order_id, :integer + end +end diff --git a/db/migrate/20170426044927_add_status_to_order_item.rb b/db/migrate/20170426044927_add_status_to_order_item.rb new file mode 100644 index 0000000000..12ce01ba6d --- /dev/null +++ b/db/migrate/20170426044927_add_status_to_order_item.rb @@ -0,0 +1,5 @@ +class AddStatusToOrderItem < ActiveRecord::Migration[5.0] + def change + add_column :order_items, :status, :string + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000000..3121014c45 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,95 @@ +# 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: 20170426044927) 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_items", force: :cascade do |t| + t.integer "category_id" + t.integer "item_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["category_id"], name: "index_categories_items_on_category_id", using: :btree + t.index ["item_id"], name: "index_categories_items_on_item_id", using: :btree + end + + create_table "items", force: :cascade do |t| + t.integer "merchant_id" + t.string "name" + t.string "description" + t.float "price" + t.integer "inventory" + t.string "photo" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "merchants", force: :cascade do |t| + t.string "username" + t.string "email" + t.integer "uid", null: false + t.string "provider", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "order_items", force: :cascade do |t| + t.integer "item_id" + t.integer "order_id" + t.integer "quantity" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "merchant_id" + t.string "status" + end + + create_table "orders", force: :cascade do |t| + t.integer "session_id" + t.string "status" + t.float "total" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "payments", force: :cascade do |t| + t.string "name_on_card" + t.string "email" + t.string "phone_num" + t.string "ship_address" + t.string "bill_address" + t.string "card_number" + t.string "expiration_date" + t.string "CCV" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "order_id" + end + + create_table "reviews", force: :cascade do |t| + t.string "description" + t.integer "rating" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "item_id" + t.index ["item_id"], name: "index_reviews_on_item_id", using: :btree + end + + add_foreign_key "reviews", "items" +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000000..1beea2accd --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,7 @@ +# 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) 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/public/404.html b/public/404.html new file mode 100644 index 0000000000..b612547fc2 --- /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..a21f82b3bd --- /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..061abc587d --- /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..3c9c7c01f3 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,5 @@ +# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file +# +# To ban all spiders from the entire site uncomment the next two lines: +# User-agent: * +# Disallow: / 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..201e697700 --- /dev/null +++ b/test/controllers/categories_controller_test.rb @@ -0,0 +1,53 @@ +require "test_helper" + +describe CategoriesController do +let(:need_login) { login_merchant(merchants(:kari)) } + + it " should get new" do + need_login + get new_category_path + must_respond_with :success + end + + it " Data should increase after creating category" do + need_login + proc { + post categories_path, params: {category: + { name: "Test"}} + }.must_change 'Category.count', 1 + end + + it " Should redirect after create" do + need_login + post categories_path params: { + category: {name: "Test"} + } + must_respond_with :redirect + must_redirect_to categories_path + end + + it " Should flash error, render template, and not increase db on failure to create " do + + proc { + need_login + post categories_path params: {category: {name: "TestCategory"}} + flash[:error].must_equal "Category could not be created" + assert :must_render_template + }.must_change 'Category.count', 0 + end + + it " Should get index" do + get categories_path + must_respond_with :success + end + + it " Should get a list of items for a secific category" do + get category_items_path(Category.first.id) + must_respond_with :success + end + + it " Should render 404 if category could not be found" do + get category_items_path(Category.last.id + 1) + assert :must_render_template + end +end diff --git a/test/controllers/items_controller_test.rb b/test/controllers/items_controller_test.rb new file mode 100644 index 0000000000..3787bb6739 --- /dev/null +++ b/test/controllers/items_controller_test.rb @@ -0,0 +1,199 @@ +require "test_helper" + +describe ItemsController do + describe "Merchant is not logged in" do + it "should get index" do + get items_path + must_respond_with :success + end + + it "should get show" do + get item_path(items(:item_one).id) + must_respond_with :success + end + + it "should show a 404 when item not found" do + get item_path(1) + must_respond_with :missing + end + end + + describe "Merchant is logged in" do + before do + login_merchant(merchants(:dan)) + end + + it "get edit form should show edit page" do + get edit_item_path(items(:item_one).id) + must_respond_with :success + end + + it "should get new form" do + get new_item_path + must_respond_with :success + end + + + + it "should redirect to list after creating item" do + Item.destroy_all + item_data = { + item: { + merchant_id: merchants(:kari).id, + name: "paid", + description: "something", + price: 25.89, + inventory: 12, + photo: "url"} + } + post items_path, params: item_data + + must_respond_with :redirect + + Item.all.length.must_equal 1 + end + + it "should get edit" do + + get edit_item_path(items(:item_one).id) + must_respond_with :success + end + + it "should get update" do + get edit_item_path(items(:item_one).id) + must_respond_with :success + end + + it "should affect the model when creating an item" do + Item.destroy_all + item_data = { + item: { + merchant_id: merchants(:kari).id, + name: "paid", + description: "something", + price: 25.89, + inventory: 12, + photo: "url"} + } + post items_path, params: item_data + + must_respond_with :redirect + + Item.all.length.must_equal 1 + + end + + + + + it "should delete an item and redirect to items list" do + + proc { + delete item_path(items(:item_one).id) + }.must_change 'Item.count', -1 + must_redirect_to items_path + end + + + it "should retire an item" do + patch retire_path(items(:item_one).id) + must_redirect_to items_path + end +end + + describe "Cart Features" do + + it "should affect the model when adding an item to cart" do + + proc { + patch add_to_cart_path(items(:item_one)), {}, {'HTTP_REFERER' => 'http://foo.com'} + }.must_change 'OrderItem.count', 1 + end + + it "should affect the model when removing an item from cart" do + + proc { + delete remove_from_cart_path(order_items(:one).id), {}, {'HTTP_REFERER' => 'http://foo.com'} + }.must_change 'OrderItem.count', -1 + + end + + it "does not create addition order_item when adding second of same item to cart" do + OrderItem.destroy_all + order_item = { + item: :item_two, + order: :one, + quantity: 1, + merchant_id: 756141187 } + patch add_to_cart_path(items(:item_two)), {}, {'HTTP_REFERER' => 'http://foo.com'}, params: order_item + + + proc { + patch add_to_cart_path(items(:item_two)), {}, {'HTTP_REFERER' => 'http://foo.com'}, params: order_item + # must_respond_with :redirect + }.must_change 'OrderItem.count', 0 + + end + + + + it "does not create additional order item if additional of same added" do + OrderItem.destroy_all + patch add_to_cart_path(items(:item_two)), {}, {'HTTP_REFERER' => 'http://foo.com'} + proc { + patch add_to_cart_path(items(:item_two)), {}, {'HTTP_REFERER' => 'http://foo.com'} + }.must_change 'OrderItem.count', 0 + end + + it "updates cart quantity should redirect" do + + item_data = { + + order_item: { + item_id: items(:item_one).id, + order_id: order_items(:one).id, + quantity: 3, + merchant_id: 756141187, + } + } + + patch order_item_path(order_items(:one).id), params: item_data + + must_redirect_to cart_path + #what else can we test here? + end + + # it " ===============does not create order item if inventory is zero ===============" do + # + # order_item_data = { + # + # order_item: { + # id: 1, + # item_id: items(:no_stock).id, + # order_id: items(:no_stock).id, + # quantity: 3, + # merchant_id: 756141187, + # } + # } + # # proc { + # patch add_to_cart_path(order_item_data), {}, {'HTTP_REFERER' => 'http://foo.com'} + # flash[:notice].must_equal "something went wrong" + # # }.must_change 'OrderItem.count', 0 + # + # # must_redirect_to :back + # end + + # it "does not create order item if invalid data" do + # + # proc { patch add_to_cart_path(items(:bad_data)), {}, {'HTTP_REFERER' => 'http://foo.com'} + # }.must_change 'OrderItem.count', 0 + # + # # must_respond_with :redirect + # # flash[:notice].must_equal "something went wrong" + # + # # must_redirect_to :back + # 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..0895727674 --- /dev/null +++ b/test/controllers/merchants_controller_test.rb @@ -0,0 +1,66 @@ + +require "test_helper" + +describe MerchantsController do + describe "index" do + it 'should get index' do + Merchant.count.must_be :>, 0 + get merchants_path + must_respond_with :success + end + end + + describe "new" do + it 'should get new page' do + get new_merchant_path + must_respond_with :success + end + end + + describe "show" do + before do + login_merchant(merchants(:dan)) + end + it "should get show" do + get merchant_path(merchants(:kari).id) + must_respond_with :success + end + + it 'should show a 404 when merchant not found' do + get merchant_path(Merchant.last.id + 1) + must_respond_with :not_found + end + end + + describe "merchant_items" do + before do + login_merchant(merchants(:dan)) + end + it "should return an array of items" do + get merchant_items_path(:dan) + must_respond_with :success + end + end + + describe "order_by_status" do + before do + login_merchant(merchants(:dan)) + end + it "takes you to the order by status page" do + get order_by_status_path(merchants(:dan).id, orders(:one).status) + must_respond_with :success + end + # How should I be testing render?? + end + + describe "ship" do + before do + login_merchant(merchants(:kari)) + end + it "should ship" do + # ship_order PUT /merchants/:id/ship/:order_item(.:format) merchants#ship + put ship_order_path(merchants(:kari).id, order_items(:two).id ) + must_respond_with :success + 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..f8bdd0f3fd --- /dev/null +++ b/test/controllers/orders_controller_test.rb @@ -0,0 +1,165 @@ +require "test_helper" + +describe OrdersController do + + describe "index" do + it "should get index" do + get orders_path + must_respond_with :redirect + end + end + + describe "show" do + it "can see show" do + get order_path(orders(:one).id) + must_respond_with :redirect + end + end + + describe "create" do + it "should create an order given valid data" do + Order.destroy_all + order_data = { + order: { + session_id: merchants(:kari).id, + status: "paid", + total: 25.89} + } + post orders_path, params: order_data + + must_respond_with :redirect + + Order.all.length.must_equal 1 + end + + it "shouldn't create an order given invalid data" do + Order.destroy_all + order_data = { + order: { + session_id: 1, + status: "you", + total: 25.89} + } + post orders_path, params: order_data + + must_respond_with :success + + Order.all.must_equal [] + end + end + + # describe "edit" do + # it "should get edit" do + # get edit_order_path + # must_respond_with :success + # end + # end + + describe "update" do + before do + login_merchant(merchants(:kari)) + end + it "should update an order given valid data" do + order_data = { + order: { + session_id: 1, + status: "complete", + total: 25.89 + } + } + + + put order_path(orders(:one).id), params: order_data + + must_respond_with :redirect + + Order.find_by_session_id(1).status.must_equal "complete" + end + + it "shouldn't update an order given invalid data" do + order_data = { + order: { + session_id: 1, + status: "you", + total: 25.89 + } + } + + put order_path(orders(:one).id), params: order_data + + must_respond_with :success + Order.find_by_session_id(1).status.must_equal "pending" + end + end + + # describe "destroy" do + # + # it "should delete an order and redirect to order list" do + # delete order_path(orders(:one).id) + # must_redirect_to orders_path + # + # Order.all.must_equal [] + # end + # end + + describe "new" do + it "should show the new order form" do + get new_order_path + must_respond_with :redirect + end + end + + describe "pay" do + it "should show the pay form" do + get pay_path(orders(:one).id) + must_respond_with :success + end + end + + describe "paid" do + it "should change the status of an order given a valid payment" do + order_to_test = orders(:one) + pymt_data = { + payment: { + name_on_card: "Joe Blow", + email: "joeblow@hotmail.com", + phone_num: "5555555555", + ship_address: "123 Amazing Street", + bill_address: "123 Amazing Street", + card_number: 1111111111111111, + expiration_date: 2222, + CCV: 333 + } + } + + post paid_path(order_to_test.id), params: pymt_data + must_respond_with :redirect + + Order.find_by_id(order_to_test.id).status.must_equal "paid" + Payment.where(order_id: order_to_test.id).length.must_equal 1 + end + + it "shouldn't create order if payment is invalid" do + order_to_test = orders(:one) + pymt_data = { + payment: { + name_on_card: "Joe Blow", + email: "joeblow@hotmail.com", + phone_num: "5555555555", + ship_address: "123 Amazing Street", + bill_address: "123 Amazing Street", + card_number: 1111111111111111, + expiration_date: 2222, + CCV: 3 + } + } + + post paid_path(order_to_test.id), params: pymt_data + must_respond_with :success + + Order.find_by_id(order_to_test.id).status.must_equal "pending" + Payment.where(order_id: order_to_test.id).length.must_equal 0 + end + end + +end diff --git a/test/controllers/payments_controller_test.rb b/test/controllers/payments_controller_test.rb new file mode 100644 index 0000000000..faae4f2b07 --- /dev/null +++ b/test/controllers/payments_controller_test.rb @@ -0,0 +1,13 @@ +require "test_helper" + +describe PaymentsController do + + + describe "confirmation" do + it "generates class variables" do + get confirmation_path(payments(:one).id) + must_respond_with :success + end + end + +end diff --git a/test/controllers/reviews_controller_test.rb b/test/controllers/reviews_controller_test.rb new file mode 100644 index 0000000000..838ae71e27 --- /dev/null +++ b/test/controllers/reviews_controller_test.rb @@ -0,0 +1,50 @@ +require "test_helper" + +describe ReviewsController do + describe "new" do + it "should show the new review form" do + get new_item_review_path(items(:item_one).id) + must_respond_with :success + end + end + + describe "create" do + it "should effect the model when creating a review with a rating" do + Review.destroy_all + review_data = { + review: { + rating: 5, + review: "yay", + item_id: items(:item_two).id + } + } + post item_path(items(:item_two).id), params: review_data + Review.all.length.must_equal 1 + end + it "should not effect the model when creating a review without a rating" do + Review.destroy_all + review_data = { + review: { + rating: 0, + review: "yay", + item_id: items(:item_two).id + } + } + post item_path(items(:item_two)), params: review_data + Review.all.length.must_equal 0 + end + it "should redirect to item show page after creating a review" do + Review.destroy_all + review_data = { + review: { + rating: 5, + review: "yay", + item_id: items(:item_two).id + } + } + post item_path(items(:item_two)), params: review_data + must_redirect_to item_path(items(:item_two)) + end + + end + end diff --git a/test/controllers/sessions_controller_test.rb b/test/controllers/sessions_controller_test.rb new file mode 100644 index 0000000000..49a3032fe2 --- /dev/null +++ b/test/controllers/sessions_controller_test.rb @@ -0,0 +1,42 @@ +require "test_helper" + +describe SessionsController do + describe "auth_callback" do + it "Can log in an existing merchant" do + proc { + login_merchant(merchants(:kari)) + must_redirect_to root_path + session[:merchant_id].must_equal merchants(:kari).id + }.must_change 'Merchant.count', 0 + end + + it "Can creat a new merchant" do + jamie = Merchant.new(username: "Jamie", uid: "999", provider: "github", email: "Jamie@adadevelopersacademy.org") + proc { + login_merchant(jamie) + must_redirect_to root_path + session[:merchant_id].must_equal Merchant.find_by(username: "Jamie").id + flash[:success].must_equal "Logged in successfully!" + }.must_change 'Merchant.count', 1 + end + + it "Cannot log in without a valid Auth_Hash" do + OmniAuth.config.mock_auth[:github] = OmniAuth::AuthHash.new({}) + proc { + get auth_github_callback_path + must_redirect_to root_path + session[:merchant_id].must_be_nil + flash[:error].must_equal "Could not log in." + }.must_change 'Merchant.count', 0 + end + end + describe "Logging out" do + it "Can log out a logged in user" do + login_merchant(merchants(:kari)) + delete logout_path + session[:merchant_id].must_be_nil + flash[:success].must_equal "You have successfully loged out" + must_redirect_to root_path + 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..08d843ded3 --- /dev/null +++ b/test/fixtures/categories.yml @@ -0,0 +1,7 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: TestCategory + +two: + name: TestCategory2 diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/fixtures/items.yml b/test/fixtures/items.yml new file mode 100644 index 0000000000..88d8362d85 --- /dev/null +++ b/test/fixtures/items.yml @@ -0,0 +1,42 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + + + +item_one: + merchant: kari + name: chips + description: tortilla + price: 4 + inventory: 20 + photo: somestring + +item_two: + merchant: dan + name: potato + description: idaho gold + price: 1.5 + inventory: 1 + photo: MyString + +no_stock: + merchant: dan + name: potato + description: idaho gold + price: 1.5 + inventory: 0 + +three: + merchant: kari + name: MyString + description: MyString + price: 5.5 + inventory: 2 + photo: MyString + +bad_data: + merchant: kari + name: MyString + description: MyString + price: qwe + inventory: none + photo: MyString diff --git a/test/fixtures/merchants.yml b/test/fixtures/merchants.yml new file mode 100644 index 0000000000..55bcaa6aae --- /dev/null +++ b/test/fixtures/merchants.yml @@ -0,0 +1,13 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +kari: + provider: github + uid: 11111 + email: kari@adadevelopersacademy.org + username: kari + +dan: + provider: github + uid: 22222 + email: dan@adadevelopersacademy.org + username: dan_the_man diff --git a/test/fixtures/order_items.yml b/test/fixtures/order_items.yml new file mode 100644 index 0000000000..cc0b3ca883 --- /dev/null +++ b/test/fixtures/order_items.yml @@ -0,0 +1,36 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + item: item_one + order: one + quantity: 4 + merchant_id: 756141187 + +two: + item: item_two + order: one + quantity: 1 + merchant_id: 756141187 + +three: + item: item_two + order: two + quantity: 1 + +four: + item: item_two + order: four + quantity: 2 + merchant_id: dan + +five: + item: item_one + order: four + quantity: 4 + merchant_id: 756141187 + +six: + item: item_one + order: five + quantity: 5 + merchant_id: 756141187 diff --git a/test/fixtures/orders.yml b/test/fixtures/orders.yml new file mode 100644 index 0000000000..9d332b28bc --- /dev/null +++ b/test/fixtures/orders.yml @@ -0,0 +1,31 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + session_id: 1 + status: "pending" + total: 20 + +two: + session_id: 2 + status: "paid" + total: 25.59 + +three: + session_id: 3 + status: "paid" + total: 10.0 + +no_pymt: + session_id: 4 + status: "pending" + total: 50.82 + +four: + session_id: 5 + status: "paid" + total: 19 + +five: + session_id: 6 + status: "paid" + total: 19 diff --git a/test/fixtures/payments.yml b/test/fixtures/payments.yml new file mode 100644 index 0000000000..6d11050f42 --- /dev/null +++ b/test/fixtures/payments.yml @@ -0,0 +1,21 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name_on_card: MyString + email: MyString + phone_num: MyString + ship_address: MyString + bill_address: MyString + card_number: MyString + expiration_date: MyString + CCV: MyString + +two: + name_on_card: MyString + email: MyString + phone_num: MyString + ship_address: MyString + bill_address: MyString + card_number: MyString + expiration_date: MyString + CCV: MyString diff --git a/test/fixtures/reviews.yml b/test/fixtures/reviews.yml new file mode 100644 index 0000000000..b2628fbeb5 --- /dev/null +++ b/test/fixtures/reviews.yml @@ -0,0 +1,26 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + item: item_one + description: Best product I've ever used! + rating: 5 + +two: + item: item_two + description: blah blah blah blah blah blah + rating: 2 + +three: + item: item_one + description: yay + rating: 2 + +four: + item: item_one + description: More reviewsMore reviewsMore reviewsMore reviewsMore reviewsMore reviewsMore reviewsMore reviewsMore reviewsMore reviewsMore reviewsMore reviewsMore reviewsMore reviewsMore reviewsMore reviewsMore reviewsMore reviewsMore reviewsMore reviewsMore reviews + rating: 3 + +five: + item: item_two + description: #having this blank might mess things up...not sure yet + rating: 4 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..c60a490258 --- /dev/null +++ b/test/models/category_test.rb @@ -0,0 +1,26 @@ +require "test_helper" + +describe Category do + + describe " validations" do + + it " Does not create a new category without name" do + category = Category.new + category.valid?.must_equal false + end + + it " Successfully create a new category" do + category = Category.new(name: "Test") + category.valid?.must_equal true + category.save + category.id?.must_equal true + category.name.must_equal "Test" + end + + it "Does not create duplicate categories" do + category = Category.new(name: categories(:one).name) + category.valid?.must_equal false + end + + end +end diff --git a/test/models/item_test.rb b/test/models/item_test.rb new file mode 100644 index 0000000000..45626c1985 --- /dev/null +++ b/test/models/item_test.rb @@ -0,0 +1,104 @@ +require 'test_helper' + +describe Item do + let(:item) { Item.new } + + + it "Cannot create a item without a name" do + item.valid?.must_equal false + #negative test + + item.errors.messages.must_include :name + #negative test + end + + + it "Can create a item with a name" do + item.name = "Taquitos" + # item.price = "123466" + # # item.merchant_id = 11 + # item.save + # + item.valid? #won't run validations until save or valid? is run + item.errors.messages[:name].must_equal [] + end + + + it "You can create a item" do + item.merchant_id = merchants(:kari).id + item.name = "Peaches" + item.price = 5 + item.inventory = 7 + item.photo = "url" + item.valid?.must_equal true + end + + it "You cannot not create a item with no price" do + item.valid?.must_equal false + #negative test + + item.errors.messages.must_include :price + #negative test + end + + + + it "You cannot not create a item with non integer inventory" do + item = Item.new + item.name = "Cheese" + item.price = 5 + item.inventory = 3.5 + item.merchant_id = merchants(:kari).id + + item.valid?.must_equal false + #negative test + + item.errors.messages.must_include :inventory + #negative test + end + + it "You cannot not create a item with negative inventory" do + item = Item.new + item.name = "Cheese" + item.price = 5 + item.inventory = -1 + item.merchant_id = merchants(:kari).id + item.valid?.must_equal false + #negative test + + item.errors.messages.must_include :inventory + #negative test + end + + it "You cannot not create a item with negative price" do + item = Item.new + item.name = "Cheese" + item.price = -5 + item.inventory = 1 + item.merchant_id = merchants(:kari).id + item.valid?.must_equal false + #negative test + + item.errors.messages.must_include :price + #negative test + end + + it "name must be unique" do + item1 = Item.new + item1.merchant_id = merchants(:kari).id + item1.name = "Jello" + item1.price = 5 + item1.inventory = 3 + item1.photo = "URL" + item1.save + item2 = Item.new + item2.merchant_id = merchants(:kari).id + item2.name = "Jello" + item2.price = 5 + item2.inventory = 3 + item2.photo = "URL" + item2.valid?.must_equal false + item2.errors.messages[:name].must_equal ["has already been taken"] + end + +end diff --git a/test/models/merchant_test.rb b/test/models/merchant_test.rb new file mode 100644 index 0000000000..e98ecb082d --- /dev/null +++ b/test/models/merchant_test.rb @@ -0,0 +1,101 @@ +require "test_helper" + +describe Merchant do + + it "Can create a new merchant" do + jamie = Merchant.new(username: "Jamie", uid: "999", provider: "github", email: "Jamie@adadevelopersacademy.org") + proc { + login_merchant(jamie) + must_redirect_to root_path + session[:merchant_id].must_equal Merchant.find_by(username: "Jamie").id + flash[:success].must_equal "Logged in successfully!" + }.must_change 'Merchant.count', 1 + end + + + describe "Merchant Relationships" do + let(:m) { merchants(:kari) } + + it " has items" do + m.items.length.must_equal 3 + m.items.first.name.must_equal items(:item_one).name + m.items.first.price.must_equal items(:item_one).price + end + + it " Has order items" do + m.order_items.count.must_be :>, 1 + m.order_items.must_include order_items(:one) + m.order_items.must_include order_items(:two) + end + + it " Does not have order items, that aren't theirs" do + m.order_items.count.must_equal 4 + m.order_items.wont_include order_items(:three) + end + end + + describe " Merchant Custom methods" do + let(:m) { merchants(:kari) } + + it " Can find all merchant orders" do + m.merchant_orders.count.must_equal 3 + m.merchant_orders.must_include orders(:one) + end + + it " Can find merchant Items by order" do + m.items_by_order(orders(:one)).must_include order_items(:one) + end + + describe " Revenue methods" do + it " Can find total merchant revenue" do + m.revenue.must_be :>, 0 + m.revenue.must_be_instance_of Float + m.revenue.must_equal 36 + end + + it " Can find revenue by status" do + m.revenue_by_status(orders(:four).status).must_be :>, 0 + end + + it " Retuns 0 if there is no revenue for a given status" do + m.revenue_by_status("complete").must_equal 0 + end + + it " Can find revenue by order" do + order = orders(:four) + order_item = order_items(:five) + + m.revenue_by_order(order).must_be :>, 0 + m.revenue_by_order(order).must_equal order_item.item.price * order_item.quantity + end + + it " Does not calculate revenue from other merchant order_items" do + order = orders(:four) + m.revenue_by_order(order).must_be :<, order.total + end + + end + describe "By Status Methods" do + it " Includes list of order statuss" do + m.order_status.count.must_equal 4 + m.order_status.must_include "paid" + m.order_status.must_include "pending" + m.order_status.must_include "complete" + m.order_status.must_include "canceled" + end + + it " Can find list of orders by status " do + m.orders_by_status(orders(:four).status).must_include orders(:four) + m.orders_by_status(orders(:four).status).count.must_be :>, 1 + end + + it " Can find a list of order items by status" do + # TODO is this method used at all? + end + + it " Can find total number of orders by status" do + m.total_orders_by_status(orders(:one).status).must_equal 1 + end + end + end +end diff --git a/test/models/order_item_test.rb b/test/models/order_item_test.rb new file mode 100644 index 0000000000..28b18ee37b --- /dev/null +++ b/test/models/order_item_test.rb @@ -0,0 +1,23 @@ +require "test_helper" + +describe OrderItem do +let(:order_item) { OrderItem.new } + + describe 'validations' do + + it "Order items require a quantity" do + + order_item.valid?.must_equal false + + order_item.errors.messages.must_include :quantity + end + + it "If a negative quantity is given, the order item is invalid" do + order_item.quantity = -1 + + order_item.valid?.must_equal false + order_item.errors.messages[:quantity].must_equal ["must be greater than 0"] + end + + end +end diff --git a/test/models/order_test.rb b/test/models/order_test.rb new file mode 100644 index 0000000000..eae174ea5e --- /dev/null +++ b/test/models/order_test.rb @@ -0,0 +1,66 @@ +require "test_helper" + +describe Order do + + describe 'validations' do + let(:order) { Order.new } + + it "Orders require a session_id, status, and total" do + + order.valid?.must_equal false + + # produces hash of all error messages + order.errors.messages.must_include :total + end + + it "If a negative total is given, the order is invalid" do + order.total = -1.45 + + order.valid?.must_equal false + order.errors.messages[:total].must_equal ["must be greater than -1"] + end + + end + + describe 'total_cost' do + it "generates the correct total for two order items" do + order = Order.find(orders(:one).id) + + order.total_cost.must_equal 17.5 + end + + it "generates the correct total for one order item" do + order = Order.find(orders(:two).id) + + order.total_cost.must_equal 1.5 + end + + it "generates the correct total for zero order items" do + order = Order.find(orders(:three).id) + + order.total_cost.must_equal 0 + end + + describe 'change_status_to_paid' do + it "changes the status of an order to paid" do + + + Order.change_status_to_paid(orders(:one).id).must_equal true + + Order.find_by_id(orders(:one).id).status.must_equal "paid" + end + end + + describe 'inventory_adjust' do + it "adjusts inventory based on item quantity bought" do + + order = Order.find(orders(:one).id) + order.inventory_adjust + + Item.find_by_id(items(:item_one).id).inventory.must_equal 16 # this locates the items in our fixtures and checks their inventory + Item.find_by_id(items(:no_stock).id).inventory.must_equal 0 + + end + end + end +end diff --git a/test/models/payment_test.rb b/test/models/payment_test.rb new file mode 100644 index 0000000000..017e8a5daf --- /dev/null +++ b/test/models/payment_test.rb @@ -0,0 +1,9 @@ +require "test_helper" + +describe Payment do + let(:payment) { Payment.new } + + it "must be valid" do + value(payment).must_be :valid? + end +end diff --git a/test/models/review_test.rb b/test/models/review_test.rb new file mode 100644 index 0000000000..a2eb100739 --- /dev/null +++ b/test/models/review_test.rb @@ -0,0 +1,56 @@ +require "test_helper" + +describe Review do + describe "Review Relationships" do + it "A review has an item" do + r = reviews(:one) + r.must_respond_to :item + r.item.must_be_kind_of Item + end + end + + describe "Review Valdations" do + let(:review) { reviews(:three) } + it "Review cannot be created without a rating" do + new_review = Review.new + new_review.valid?.must_equal false + end + it "If not rating then review isn't valid" do + review.rating = nil + review.valid?.must_equal false + review.errors.messages.must_include :rating + end + + it "Rating cannot be less than 1" do + bad_review = Review.new(rating: 0) + bad_review.save + bad_review.valid?.must_equal false + + end + it "Rating cannot be greater than 5" do + another_bad_review = Review.new(rating: 0) + another_bad_review.save + another_bad_review.valid?.must_equal false + end + it "If rating is given, the review is valid" do + review.rating = 4 + review.errors.messages[:rating].must_equal [] + end + it "Review will be created if rating is present and an integer" do + item = Item.new + item.name = "Coconut oil" + item.price = 4.30 + item.photo = "pic" + item.merchant_id = merchants(:kari).id + item.inventory = 5 + item.save + review = Review.new + review.rating = 4 + review.description = "Great product" + review.item_id = item.id + review.save + + review.valid?.must_equal true + end + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000000..1f220aa20d --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,48 @@ +require 'simplecov' +SimpleCov.start + +ENV["RAILS_ENV"] = "test" +require File.expand_path("../../config/environment", __FILE__) +require "rails/test_help" +require "minitest/rails" +require "minitest/reporters" + +# 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 login_merchant(merchant) + OmniAuth.config.mock_auth[:github] = OmniAuth::AuthHash.new(mock_auth_hash(merchant)) + + get auth_github_callback_path + end + + def mock_auth_hash(merchant) + return { + provider: merchant.provider, + uid: merchant.uid, + info: { + email: merchant.email, + nickname: merchant.username + } + } + end + + def setup + OmniAuth.config.test_mode = true + end +end diff --git a/tmp/.keep b/tmp/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/assets/javascripts/.keep b/vendor/assets/javascripts/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/assets/stylesheets/.keep b/vendor/assets/stylesheets/.keep new file mode 100644 index 0000000000..e69de29bb2