diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000..256f734719 Binary files /dev/null and b/.DS_Store differ diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE index a57f5ec408..f9f305c8fd 100644 --- a/.github/PULL_REQUEST_TEMPLATE +++ b/.github/PULL_REQUEST_TEMPLATE @@ -4,12 +4,12 @@ Congratulations! You're submitting your assignment! These comprehension question ## Comprehension Questions | Question | Answer | | :------------- | :------------- | -| How did your team break up the work to be done? | | -| How did your team utilize git to collaborate? | | -| What did your group do to try to keep your code DRY while many people collaborated on it? | | -| What was a technical challenge that you faced as a group? | | -| What was a team/personal challenge that you faced as a group? | | -| What could your team have done better? | | -| What was your application's ERD? (include a link) | | -| What is your Trello URL? | | -| What is the Heroku URL of your deployed application? | | +| How did your team break up the work to be done? | We started with assigning people to Trello cards. the models and controllers for testing and creating the methods. We set up the tasks in waves on Trello and as we completed the tasks, we moved on to different tasks in the waves. | +| How did your team utilize git to collaborate? | We used to git to work on different branches based on features and tests. We then did a collaborative merge, pull, push after each day's stand up. | +| What did your group do to try to keep your code DRY while many people collaborated on it? | We tried switching focus areas, such as products and orders, when we started our testing, that way we were reviewing other team member's models and controllers and would essentially proof each other's code to DRY it up. We also used before actions and custom methods that helped us dry the code up. | +| What was a technical challenge that you faced as a group? | Deploying to Heroku. We had trouble logging in with git and with our database. We reviewed the Heroku logs and StackOverflow to determine the solutions. | +| What was a team/personal challenge that you faced as a group? | We think we did a good job overall with ask and guess culture. It was a challenge having a group member out for 2 days, but as a group, we feel we communicated well over Slack to move forward with the project. | +| What could your team have done better? | Deployed earlier to work out those issues. | +| What was your application's ERD? (include a link) | We will Slack the photos of the ERD. We did it on the white board as opposed to electronically. | +| What is your Trello URL? | https://trello.com/b/d42fqbbE/whythehexnots | +| What is the Heroku URL of your deployed application? | http://sourceress.herokuapp.com/ | diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..42c3e6965b --- /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 + +/node_modules +/yarn-error.log + +.byebug_history +.env + +public/assets/** + +/coverage/ diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000000..fb715a7d4f --- /dev/null +++ b/Gemfile @@ -0,0 +1,77 @@ +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 + +gem 'awesome_print' +gem "paperclip", "~> 5.0.0" +gem 'omniauth' +gem 'omniauth-github' +gem 'simplecov' + +# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' +gem 'rails', '~> 5.1.4' +# Use postgresql as the database for Active Record +gem 'pg', '~> 0.18' +# Use Puma as the app server +gem 'puma', '~> 3.7' +# Use SCSS for stylesheets +gem 'sass-rails', '~> 5.0' +# Use Uglifier as compressor for JavaScript assets +gem 'uglifier', '>= 1.3.0' +# See https://github.com/rails/execjs#readme for more supported runtimes +# gem 'therubyracer', platforms: :ruby + +# Use CoffeeScript for .coffee assets and views +# gem 'coffee-rails', '~> 4.2' +# 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', platforms: [:mri, :mingw, :x64_mingw] + # Adds support for Capybara system testing and selenium driver + gem 'capybara', '~> 2.13' + gem 'selenium-webdriver' + gem 'dotenv-rails' + gem 'simplecov' + gem 'pry-rails' +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', '< 3.2' + # 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] + +gem 'jquery-turbolinks' +gem 'foundation-rails', '6.4.1.2' +group :development do + gem 'better_errors' + + gem 'binding_of_caller' +end + +group :test do + gem 'minitest-rails' + gem 'minitest-reporters' +end + +gem 'jquery-rails' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000000..c8936fbe9d --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,286 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (5.1.4) + actionpack (= 5.1.4) + nio4r (~> 2.0) + websocket-driver (~> 0.6.1) + actionmailer (5.1.4) + actionpack (= 5.1.4) + actionview (= 5.1.4) + activejob (= 5.1.4) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 2.0) + actionpack (5.1.4) + actionview (= 5.1.4) + activesupport (= 5.1.4) + rack (~> 2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.2) + actionview (5.1.4) + activesupport (= 5.1.4) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.0.3) + activejob (5.1.4) + activesupport (= 5.1.4) + globalid (>= 0.3.6) + activemodel (5.1.4) + activesupport (= 5.1.4) + activerecord (5.1.4) + activemodel (= 5.1.4) + activesupport (= 5.1.4) + arel (~> 8.0) + activesupport (5.1.4) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (~> 0.7) + minitest (~> 5.1) + tzinfo (~> 1.1) + addressable (2.5.2) + public_suffix (>= 2.0.2, < 4.0) + ansi (1.5.0) + arel (8.0.0) + awesome_print (1.8.0) + babel-source (5.8.35) + babel-transpiler (0.7.0) + babel-source (>= 4.0, < 6) + execjs (~> 2.0) + better_errors (2.4.0) + coderay (>= 1.0.0) + erubi (>= 1.0.0) + 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.1.0) + capybara (2.15.4) + addressable + mini_mime (>= 0.1.3) + nokogiri (>= 1.3.3) + rack (>= 1.0.0) + rack-test (>= 0.5.4) + xpath (~> 2.0) + childprocess (0.8.0) + ffi (~> 1.0, >= 1.0.11) + climate_control (0.2.0) + cocaine (0.5.8) + climate_control (>= 0.0.3, < 1.0) + coderay (1.1.2) + concurrent-ruby (1.0.5) + crass (1.0.2) + debug_inspector (0.0.3) + docile (1.1.5) + dotenv (2.2.1) + dotenv-rails (2.2.1) + dotenv (= 2.2.1) + railties (>= 3.2, < 5.2) + erubi (1.7.0) + execjs (2.7.0) + faraday (0.12.2) + multipart-post (>= 1.2, < 3) + ffi (1.9.18) + foundation-rails (6.4.1.2) + 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.6) + i18n (0.9.0) + concurrent-ruby (~> 1.0) + jbuilder (2.7.0) + activesupport (>= 4.2.0) + multi_json (>= 1.2) + jquery-rails (4.3.1) + rails-dom-testing (>= 1, < 3) + railties (>= 4.2.0) + thor (>= 0.14, < 2.0) + jquery-turbolinks (2.1.0) + railties (>= 3.1.0) + turbolinks + json (2.0.2) + jwt (1.5.6) + listen (3.1.5) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + ruby_dep (~> 1.2) + loofah (2.1.1) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.6.6) + mime-types (>= 1.16, < 4) + method_source (0.9.0) + mime-types (3.1) + mime-types-data (~> 3.2015) + mime-types-data (3.2016.0521) + mimemagic (0.3.2) + mini_mime (0.1.4) + mini_portile2 (2.3.0) + minitest (5.10.3) + minitest-rails (3.0.0) + minitest (~> 5.8) + railties (~> 5.0) + minitest-reporters (1.1.18) + ansi + builder + minitest (>= 5.0) + ruby-progressbar + multi_json (1.12.2) + multi_xml (0.6.0) + multipart-post (2.0.0) + nio4r (2.1.0) + nokogiri (1.8.1) + mini_portile2 (~> 2.3.0) + oauth2 (1.4.0) + faraday (>= 0.8, < 0.13) + jwt (~> 1.0) + multi_json (~> 1.3) + multi_xml (~> 0.5) + rack (>= 1.2, < 3) + omniauth (1.7.1) + hashie (>= 3.4.6, < 3.6.0) + rack (>= 1.6.2, < 3) + omniauth-github (1.3.0) + omniauth (~> 1.5) + omniauth-oauth2 (>= 1.4.0, < 2.0) + omniauth-oauth2 (1.4.0) + oauth2 (~> 1.0) + omniauth (~> 1.2) + paperclip (5.0.0) + activemodel (>= 4.2.0) + activesupport (>= 4.2.0) + cocaine (~> 0.5.5) + mime-types + mimemagic (~> 0.3.0) + pg (0.21.0) + pry (0.11.1) + coderay (~> 1.1.0) + method_source (~> 0.9.0) + pry-rails (0.3.6) + pry (>= 0.10.4) + public_suffix (3.0.0) + puma (3.10.0) + rack (2.0.3) + rack-test (0.7.0) + rack (>= 1.0, < 3) + rails (5.1.4) + actioncable (= 5.1.4) + actionmailer (= 5.1.4) + actionpack (= 5.1.4) + actionview (= 5.1.4) + activejob (= 5.1.4) + activemodel (= 5.1.4) + activerecord (= 5.1.4) + activesupport (= 5.1.4) + bundler (>= 1.3.0) + railties (= 5.1.4) + sprockets-rails (>= 2.0.0) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.0.3) + loofah (~> 2.0) + railties (5.1.4) + actionpack (= 5.1.4) + activesupport (= 5.1.4) + method_source + rake (>= 0.8.7) + thor (>= 0.18.1, < 2.0) + rake (12.1.0) + rb-fsevent (0.10.2) + rb-inotify (0.9.10) + ffi (>= 0.5.0, < 2) + ruby-progressbar (1.9.0) + ruby_dep (1.5.0) + rubyzip (1.2.1) + sass (3.4.25) + 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) + selenium-webdriver (3.6.0) + childprocess (~> 0.5) + rubyzip (~> 1.0) + simplecov (0.15.1) + docile (~> 1.1.0) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.2) + spring (2.0.2) + 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.1) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) + thor (0.20.0) + thread_safe (0.3.6) + tilt (2.0.8) + turbolinks (5.0.1) + turbolinks-source (~> 5) + turbolinks-source (5.0.3) + tzinfo (1.2.3) + thread_safe (~> 0.1) + uglifier (3.2.0) + execjs (>= 0.3.0, < 3) + web-console (3.5.1) + 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) + xpath (2.1.0) + nokogiri (~> 1.3) + +PLATFORMS + ruby + +DEPENDENCIES + awesome_print + better_errors + binding_of_caller + byebug + capybara (~> 2.13) + dotenv-rails + foundation-rails (= 6.4.1.2) + jbuilder (~> 2.5) + jquery-rails + jquery-turbolinks + listen (>= 3.0.5, < 3.2) + minitest-rails + minitest-reporters + omniauth + omniauth-github + paperclip (~> 5.0.0) + pg (~> 0.18) + pry-rails + puma (~> 3.7) + rails (~> 5.1.4) + sass-rails (~> 5.0) + selenium-webdriver + simplecov + spring + spring-watcher-listen (~> 2.0.0) + turbolinks (~> 5) + tzinfo-data + uglifier (>= 1.3.0) + web-console (>= 3.3.0) + +BUNDLED WITH + 1.16.0.pre.2 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/javascripts/application.js b/app/assets/javascripts/application.js new file mode 100644 index 0000000000..7c05a81230 --- /dev/null +++ b/app/assets/javascripts/application.js @@ -0,0 +1,22 @@ +// 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, 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 rails-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..739aa5f022 --- /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.js b/app/assets/javascripts/categories.js new file mode 100644 index 0000000000..dee720facd --- /dev/null +++ b/app/assets/javascripts/categories.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. 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/merchants.js b/app/assets/javascripts/merchants.js new file mode 100644 index 0000000000..dee720facd --- /dev/null +++ b/app/assets/javascripts/merchants.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/javascripts/orders.js b/app/assets/javascripts/orders.js new file mode 100644 index 0000000000..dee720facd --- /dev/null +++ b/app/assets/javascripts/orders.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/javascripts/products.js b/app/assets/javascripts/products.js new file mode 100644 index 0000000000..dee720facd --- /dev/null +++ b/app/assets/javascripts/products.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/javascripts/reviews.js b/app/assets/javascripts/reviews.js new file mode 100644 index 0000000000..dee720facd --- /dev/null +++ b/app/assets/javascripts/reviews.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/javascripts/sessions.js b/app/assets/javascripts/sessions.js new file mode 100644 index 0000000000..dee720facd --- /dev/null +++ b/app/assets/javascripts/sessions.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/stylesheets/_settings.scss b/app/assets/stylesheets/_settings.scss new file mode 100644 index 0000000000..b67ff00cdc --- /dev/null +++ b/app/assets/stylesheets/_settings.scss @@ -0,0 +1,863 @@ +// 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. Flexbox Utilities +// 20. Forms +// 21. Label +// 22. Media Object +// 23. Menu +// 24. Meter +// 25. Off-canvas +// 26. Orbit +// 27. Pagination +// 28. Progress Bar +// 29. Prototype Arrow +// 30. Prototype Border-Box +// 31. Prototype Border-None +// 32. Prototype Bordered +// 33. Prototype Display +// 34. Prototype Font-Styling +// 35. Prototype List-Style-Type +// 36. Prototype Overflow +// 37. Prototype Position +// 38. Prototype Rounded +// 39. Prototype Separator +// 40. Prototype Shadow +// 41. Prototype Sizing +// 42. Prototype Spacing +// 43. Prototype Text-Decoration +// 44. Prototype Text-Transformation +// 45. Prototype Text-Utilities +// 46. Responsive Embed +// 47. Reveal +// 48. Slider +// 49. Switch +// 50. Table +// 51. Tabs +// 52. Thumbnail +// 53. Title Bar +// 54. Tooltip +// 55. Top Bar +// 56. Xy Grid + +@import 'util/util'; + +// 1. Global +// --------- + +$global-font-size: 100%; +$global-width: rem-calc(1200); +$global-lineheight: 1.5; +$foundation-palette: ( + primary: #1779ba, + secondary: #767676, + success: #3adb76, + warning: #ffae00, + alert: #cc4b37, +); +$light-gray: #e6e6e6; +$medium-gray: #cacaca; +$dark-gray: #8a8a8a; +$black: #0a0a0a; +$white: #fefefe; +$body-background: $white; +$body-font-color: $black; +$body-font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; +$body-antialiased: true; +$global-margin: 1rem; +$global-padding: 1rem; +$global-position: 1rem; +$global-weight-normal: normal; +$global-weight-bold: bold; +$global-radius: 0; +$global-menu-padding: 0.7rem 1rem; +$global-menu-nested-margin: 1rem; +$global-text-direction: ltr; +$global-flexbox: true; +$global-prototype-breakpoints: false; +$global-color-pick-contrast-tolerance: 0; +$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; +$grid-column-alias: 'columns'; +$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: inherit; +$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: $medium-gray; +$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: $dark-gray; +$blockquote-padding: rem-calc(9 20 0 19); +$blockquote-border: 1px solid $medium-gray; +$cite-font-size: rem-calc(13); +$cite-color: $dark-gray; +$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: $dark-gray; +$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: $light-gray; +$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-padding: $global-menu-padding; +$accordionmenu-nested-margin: $global-menu-nested-margin; +$accordionmenu-submenu-padding: $accordionmenu-padding; +$accordionmenu-arrows: true; +$accordionmenu-arrow-color: $primary-color; +$accordionmenu-item-background: null; +$accordionmenu-border: null; +$accordionmenu-submenu-toggle-background: null; +$accordion-submenu-toggle-border: $accordionmenu-border; +$accordionmenu-submenu-toggle-width: 40px; +$accordionmenu-submenu-toggle-height: $accordionmenu-submenu-toggle-width; +$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-separator: true; +$breadcrumbs-item-separator-item: '/'; +$breadcrumbs-item-separator-item-rtl: '\\'; +$breadcrumbs-item-separator-color: $medium-gray; + +// 11. Button +// ---------- + +$button-font-family: inherit; +$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-hollow-border-width: 1px; +$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-bottom: $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-padding: $global-menu-padding; +$drilldown-nested-margin: 0; +$drilldown-background: $white; +$drilldown-submenu-padding: $drilldown-padding; +$drilldown-submenu-background: $white; +$drilldown-arrow-color: $primary-color; +$drilldown-arrow-size: 6px; + +// 17. Dropdown +// ------------ + +$dropdown-padding: 1rem; +$dropdown-background: $body-background; +$dropdown-border: 1px solid $medium-gray; +$dropdown-font-size: 1rem; +$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-arrow-padding: 1.5rem; +$dropdownmenu-min-width: 200px; +$dropdownmenu-background: $white; +$dropdownmenu-submenu-background: $dropdownmenu-background; +$dropdownmenu-padding: $global-menu-padding; +$dropdownmenu-nested-margin: 0; +$dropdownmenu-submenu-padding: $dropdownmenu-padding; +$dropdownmenu-border: 1px solid $medium-gray; +$dropdown-menu-item-color-active: get-color(primary); +$dropdown-menu-item-background-active: transparent; + +// 19. Flexbox Utilities +// --------------------- + +$flex-source-ordering-count: 6; +$flexbox-responsive-breakpoints: true; + +// 20. 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: $black; +$helptext-font-size: rem-calc(13); +$helptext-font-style: italic; +$input-prefix-color: $black; +$input-prefix-background: $light-gray; +$input-prefix-border: 1px solid $medium-gray; +$input-prefix-padding: 1rem; +$form-label-color: $black; +$form-label-font-size: rem-calc(14); +$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: $black; +$input-placeholder-color: $medium-gray; +$input-font-family: inherit; +$input-font-size: rem-calc(16); +$input-font-weight: $global-weight-normal; +$input-line-height: $global-lineheight; +$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-padding: $form-spacing / 2; +$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; + +// 21. 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; + +// 22. Media Object +// ---------------- + +$mediaobject-margin-bottom: $global-margin; +$mediaobject-section-padding: $global-padding; +$mediaobject-image-width-stacked: 100%; + +// 23. Menu +// -------- + +$menu-margin: 0; +$menu-nested-margin: $global-menu-nested-margin; +$menu-items-padding: $global-menu-padding; +$menu-simple-margin: 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-state-back-compat: true; +$menu-centered-back-compat: true; + +// 24. 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; + +// 25. Off-canvas +// -------------- + +$offcanvas-size: 250px; +$offcanvas-vertical-size: 250px; +$offcanvas-background: $light-gray; +$offcanvas-shadow: 0 0 10px rgba($black, 0.7); +$offcanvas-inner-shadow-size: 20px; +$offcanvas-inner-shadow-color: rgba($black, 0.25); +$offcanvas-overlay-zindex: 11; +$offcanvas-push-zindex: 12; +$offcanvas-overlap-zindex: 13; +$offcanvas-reveal-zindex: 12; +$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'; + +// 26. 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; + +// 27. 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; + +// 28. Progress Bar +// ---------------- + +$progress-height: 1rem; +$progress-background: $medium-gray; +$progress-margin-bottom: $global-margin; +$progress-meter-background: $primary-color; +$progress-radius: $global-radius; + +// 29. Prototype Arrow +// ------------------- + +$prototype-arrow-directions: ( + down, + up, + right, + left +); +$prototype-arrow-size: 0.4375rem; +$prototype-arrow-color: $black; + +// 30. Prototype Border-Box +// ------------------------ + +$prototype-border-box-breakpoints: $global-prototype-breakpoints; + +// 31. Prototype Border-None +// ------------------------- + +$prototype-border-none-breakpoints: $global-prototype-breakpoints; + +// 32. Prototype Bordered +// ---------------------- + +$prototype-bordered-breakpoints: $global-prototype-breakpoints; +$prototype-border-width: rem-calc(1); +$prototype-border-type: solid; +$prototype-border-color: $medium-gray; + +// 33. Prototype Display +// --------------------- + +$prototype-display-breakpoints: $global-prototype-breakpoints; +$prototype-display: ( + inline, + inline-block, + block, + table, + table-cell +); + +// 34. Prototype Font-Styling +// -------------------------- + +$prototype-font-breakpoints: $global-prototype-breakpoints; +$prototype-wide-letter-spacing: rem-calc(4); +$prototype-font-normal: $global-weight-normal; +$prototype-font-bold: $global-weight-bold; + +// 35. Prototype List-Style-Type +// ----------------------------- + +$prototype-list-breakpoints: $global-prototype-breakpoints; +$prototype-style-type-unordered: ( + disc, + circle, + square +); +$prototype-style-type-ordered: ( + decimal, + lower-alpha, + lower-latin, + lower-roman, + upper-alpha, + upper-latin, + upper-roman +); + +// 36. Prototype Overflow +// ---------------------- + +$prototype-overflow-breakpoints: $global-prototype-breakpoints; +$prototype-overflow: ( + visible, + hidden, + scroll +); + +// 37. Prototype Position +// ---------------------- + +$prototype-position-breakpoints: $global-prototype-breakpoints; +$prototype-position: ( + static, + relative, + absolute, + fixed +); +$prototype-position-z-index: 975; + +// 38. Prototype Rounded +// --------------------- + +$prototype-rounded-breakpoints: $global-prototype-breakpoints; +$prototype-border-radius: rem-calc(3); + +// 39. Prototype Separator +// ----------------------- + +$prototype-separator-breakpoints: $global-prototype-breakpoints; +$prototype-separator-align: center; +$prototype-separator-height: rem-calc(2); +$prototype-separator-width: 3rem; +$prototype-separator-background: $primary-color; +$prototype-separator-margin-top: $global-margin; + +// 40. Prototype Shadow +// -------------------- + +$prototype-shadow-breakpoints: $global-prototype-breakpoints; +$prototype-box-shadow: 0 2px 5px 0 rgba(0,0,0,.16), + 0 2px 10px 0 rgba(0,0,0,.12); + +// 41. Prototype Sizing +// -------------------- + +$prototype-sizing-breakpoints: $global-prototype-breakpoints; +$prototype-sizing: ( + width, + height +); +$prototype-sizes: ( + 25: 25%, + 50: 50%, + 75: 75%, + 100: 100% +); + +// 42. Prototype Spacing +// --------------------- + +$prototype-spacing-breakpoints: $global-prototype-breakpoints; +$prototype-spacers-count: 3; + +// 43. Prototype Text-Decoration +// ----------------------------- + +$prototype-decoration-breakpoints: $global-prototype-breakpoints; +$prototype-text-decoration: ( + overline, + underline, + line-through, +); + +// 44. Prototype Text-Transformation +// --------------------------------- + +$prototype-transformation-breakpoints: $global-prototype-breakpoints; +$prototype-text-transformation: ( + lowercase, + uppercase, + capitalize +); + +// 45. Prototype Text-Utilities +// ---------------------------- + +$prototype-utilities-breakpoints: $global-prototype-breakpoints; +$prototype-text-overflow: ellipsis; + +// 46. Responsive Embed +// -------------------- + +$responsive-embed-margin-bottom: rem-calc(16); +$responsive-embed-ratios: ( + default: 4 by 3, + widescreen: 16 by 9, +); + +// 47. 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); + +// 48. 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; + +// 49. 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; + +// 50. 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; +$table-stack-breakpoint: medium; + +// 51. 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; + +// 52. 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; + +// 53. 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; + +// 54. Tooltip +// ----------- + +$has-tip-cursor: help; +$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-max-width: 10rem; +$tooltip-font-size: $small-font-size; +$tooltip-pip-width: 0.75rem; +$tooltip-pip-height: $tooltip-pip-width * 0.866; +$tooltip-radius: $global-radius; + +// 55. 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; + +// 56. Xy Grid +// ----------- + +$xy-grid: true; +$grid-container: $global-width; +$grid-columns: 12; +$grid-margin-gutters: ( + small: 20px, + medium: 30px +); +$grid-padding-gutters: $grid-margin-gutters; +$grid-container-padding: $grid-padding-gutters; +$grid-container-max: $global-width; +$block-grid-max: 8; + diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss new file mode 100644 index 0000000000..38bc2bc1bc --- /dev/null +++ b/app/assets/stylesheets/application.scss @@ -0,0 +1,602 @@ +/* +* 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, 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 foundation_and_overrides +*= require_tree . + +/*general element styling*/ +ul, ol { + list-style: none; +} + +html { + width: 100%; + height: 100%; +} + +body { + width: 100%; + // background-color: black; + background: radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%); + color: white; + font-family: 'Josefin Slab', serif; +} + +em { + font-weight: bold; + font-style: normal; +} + +a, a:visited { + color: inherit; +} + +a:hover { + color: grey; +} + +/*flash message styling*/ +.flash, .status { + border-radius: 5px; + padding: 20px 25px; + background-color: transparent; + color: white; + font-size: 1.25rem; + font-family: 'Josefin Slab', serif; + text-align: center; +} + +/*application wide header & dropdown menus*/ +header { + width: 100%; + margin-left: 0; + margin-right: 0; + padding-top: 1.5rem; + padding-bottom: 5rem; + display: flex; + justify-content: space-evenly; + align-items: center; +} + +@media screen and (max-width: 480px) { + html { + background-color: black; + } + + #stars, #stars2, #stars3 { + display: none + } + + .logo { + display: none + } + + .dropdown ul { + // display: none; + } +} + +.logo a, .home-link { + /*font-family: 'Berkshire Swash', cursive;*/ + font-family: 'Cinzel', serif; + color: white; + text-shadow: 10px; + font-weight: bold; + font-size: 4rem; + float: left; + transition: all .2s ease-in-out; +} + +.dropdown { + position: relative; + display: flex; + text-align: left; + margin-left: 0; +} + +.navigation .dropdown button { + font-family: 'Cinzel', serif; + font-size: 2em; + text-shadow: 1; + text-decoration: none; +} + +.dropdown-button-browse, .dropdown-button-cart, .dropdown-button-login { + color: white; + padding: 0; + font-size: 3em; + border: none; + cursor: pointer; + font-weight: bolder; + margin: 0; + transition: all .2s ease-in-out; +} + +.dropdown-button-browse:hover, .dropdown-button-cart:hover, .dropdown-button-login:hover, .logo a:hover { + transform: scale(1.15); +} + +.dropdown-content-browse, .dropdown-content-cart, .dropdown-content-login { + display: none; + position: absolute; + font-family: 'Josefin Slab', serif; + color: white; + text-transform: capitalize; + font-size: 1.5rem; + width: 20em; + min-width: 160px; + text-align: left; + overflow: visible; + margin: 0; + z-index: 1; + transition: all .2s ease-in-out; +} + +.dropdown-content-browse a, .dropdown-content-cart, .dropdown-content-login a { + padding: 12px 16px; + text-decoration: none; + width: 8em; + display: block; + transition: all .1s ease-in; +} + +.dropdown-content-browse a:hover, .dropdown-content-merchant a:hover, .dropdown-content-cart, .dropdown-content-login a { + color: black; + width: 8em; + background-color: darkgrey; +} + +.dropdown:hover .dropdown-content-browse { + display: block; +} + +.dropdown:hover .dropdown-content-cart { + display: block; +} + +.dropdown:hover .dropdown-content-cart { + display: block; +} + +/*content container across all pages*/ +.content { + width: 100%; + display: inline-block; + margin: 2rem; +} + +/*index views for all models*/ +.all-products, .all-merchants, .all-categories, .show-merchant, .show-category, .home { + display: flex; + flex-flow: row; + flex-wrap: wrap; + margin: 0; + color: white; + text-align: center; + justify-content: center; +} + +.index-banner { + width: 100%; + text-align: center; + padding: 1rem; + margin-bottom: 1.5rem; + font-family: 'Cinzel', serif; + font-size: 3em; + text-shadow: 1; +} + +.index-banner .email { + font-size: 2.5rem; +} + +.index-image { + height: 250px; + width: 260px; + overflow: hidden; + margin-right: 0; + padding-right: 0; + padding-bottom: 1rem; +} + +.merchant .index-image { + height: 195px; + width: 260px; +} + +.index-image:hover { + -webkit-filter: grayscale(100%); + filter: grayscale(100%); +} + +.info-card { + clear: both; + height: 400px; + width: 275px; + overflow: hidden; + transition: all .2s ease-in; + font-size: 1.5rem; +} + +.info-card .merchant { + font-size: 1rem; +} + +.info-card:hover { + transform: scale(1.15); +} + +.product, .merchant, .category { + display: flex; + flex-flow: column; + padding: 1em; + text-align: left; + color: white; + font-family: 'Josefin Slab', serif; + width: 25rem; + height: 30rem; + margin: 1rem; +} + +.category-name em { + text-align: center; + font-size: 1.5rem; +} + +/*index views for all models*/ +.show { + display: inline-block; + width: 100%; +} + +.image-details-combo { + display: inline-block; + width: 100%; +} + +.show-details { + margin-top: 2rem; + margin-left: 5rem; +} + +.show-details p { + /*display: inline-block;*/ + font-family: 'Josefin Slab', serif; + color: white; + font-size: 2rem; + line-height: 120%; +} + +.show-details button { + display: block; +} + +.show-image { + display: inline; +} + +.show-image img { + display: inline-block; + width: 500px; + height: 500px; +} + +// reviews for show product page +.one-review { + background-color: darkgrey; + color: black; + border-radius: 5px; + font-size: 3rem; +} + +/*homepage background image*/ +#homepage { + background-image: radial-gradient(transparent, rgba(0,0,0,.8)), url("http://1.bp.blogspot.com/-kLbhA08qOUw/Vi5FAnWvs9I/AAAAAAAABBE/vrAlIqU9emk/s1600/seances.jpg%22"); + min-height: 100%; + background-position: center center; + background-repeat: no-repeat; + background-color: black; + background-size: 100% 100%; +} + +.home-link { + width: 100%; + color: white; + font-size: 6rem; + display: inline-block; + text-align: center; + position: relative; + margin-bottom: 0; + letter-spacing: 7px; +} +/*homepage canvas crystal ball*/ +#myCanvas { + display: inline-block; + width: 100%; + height: 100%; + margin: 0; + border-radius: 80%; + position: relative; + background: transparent; +} + +.ball { + display: inline-block; + width: 35%; + height: 35%; + margin-right: 32.5%; + margin-left: 32.5%; + margin-bottom: 10%; + border-radius: 50%; + position: relative; + background: radial-gradient(circle at 50% 120%, #4f0e71, #430b5f 10%, #3d0a56 80%, #240633 100%); + opacity: .85; +} + +.ball:before { + content: ""; + position: absolute; + top: 1%; + left: 5%; + width: 90%; + height: 90%; + border-radius: 50%; + background: radial-gradient(circle at 50% 0px, #ffffff, rgba(255, 255, 255, 0) 58%); + -webkit-filter: blur(5px); + z-index: 2; +} + +.ball .shadow { + position: absolute; + width: 100%; + height: 100%; + background: radial-gradient(circle at 50% 50%, rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.1) 40%, rgba(0, 0, 0, 0) 50%); + -webkit-transform: rotateX(90deg) translateZ(-150px); + -moz-transform: rotateX(90deg) translateZ(-150px); + -ms-transform: rotateX(90deg) translateZ(-150px); + -o-transform: rotateX(90deg) translateZ(-150px); + transform: rotateX(90deg) translateZ(-150px); + z-index: -1; +} + +/*order page details*/ +.order { + width: 100%; + text-align: center; +} + +.order-details, form { + width: 70%; + margin-left: 20%; + margin-right: 20%; + padding-top: 1rem; + text-align: left; +} + +.order-details { + font-size: 1.5rem; +} + +.line-item { + width: 100%; + display: inline-block; +} + +.product-info { + float: left; + text-align: center; +} + +.order-info { + float: left; + text-align: left; +} + +.change-amount { + float: right; + display: inline-block; +} + +.revenue { + font-size: 1.5rem; + padding: 1em; +} + +// merchant views +.view-buttons { + display: inline-block; + align-items: center; +} + +/*button styling*/ +.button, input[type=text], input[type=submit] { + flex: 1 1 auto; + margin: 10px; + padding: 20px; + border: 2px solid grey; + text-align: center; + font-family: 'Josefin Slab', serif; + text-transform: uppercase; + font-weight: bolder; + color: white; + background-color: transparent; + position: relative; + overflow:hidden; + transition: .3s; +} + + +.button:hover, input[type=submit]:hover { + color: black; + background-color: white; + transform: scale(1.15); +} + +// form styling +label { + color: white; + font-size: 1.5rem; +} + +input[type=text], input[type=text]:focus, textarea, textarea:focus { + background-color: transparent; + color: white; +} + +/*featured product homepage slider*/ +.scrolling-image { + display: block; + text-align: center; +} + +#slider { + position: relative; + overflow: hidden; + margin: 20px auto 0 auto; + border-radius: 4px; + width: 80%; + transition: all .2s ease-in-out; +} + +#slider ul { + position: relative; + margin: 0; + padding: 0; + height: 200px; + list-style: none; +} + +#slider ul li { + position: relative; + display: block; + float: left; + margin: 0; + padding: 0; + width: 600px; + height: 300px; + background: #ccc; + text-align: center; + line-height: 300px; +} + +a.control_prev, a.control_next { + position: absolute; + top: 40%; + z-index: 999; + display: block; + padding: 4% 3%; + width: auto; + height: auto; + background: #2a2a2a; + color: #fff; + text-decoration: none; + font-weight: 600; + font-size: 18px; + opacity: 0.8; + cursor: pointer; +} + +a.control_prev:hover, a.control_next:hover { + opacity: 1; + -webkit-transition: all 0.2s ease; +} + +a.control_prev { + border-radius: 0 2px 2px 0; +} + +a.control_next { + right: 0; + border-radius: 2px 0 0 2px; +} + +.slider_option { + display: block; + position: absolute; + margin: 10px auto; + width: 160px; + font-size: 18px; +} + +.slider-link { + position: absolute; +} + +#checkbox { + display: none; +} + + +// funexciting but ultimately unnecessary parralax background so comment out below this point if you need to for fun/sanity + +html { + height: 100%; + background: radial-gradient(ellipse at bottom, #1b2735 0%, #090a0f 100%); + // overflow: hidden; +} + +#stars { + content:""; + background: transparent; + box-shadow: 1744px 122px #FFF , 134px 1321px #FFF , 92px 859px #FFF , 235px 1045px #FFF , 366px 912px #FFF , 491px 942px #FFF , 14px 1831px #FFF , 582px 476px #FFF , 588px 1230px #FFF , 1520px 1343px #FFF , 1671px 203px #FFF , 550px 341px #FFF , 1491px 549px #FFF , 558px 161px #FFF , 896px 1823px #FFF , 999px 1463px #FFF , 1557px 636px #FFF , 1754px 1307px #FFF , 1682px 1494px #FFF , 703px 1707px #FFF , 1945px 1847px #FFF , 1151px 1320px #FFF , 980px 144px #FFF , 478px 948px #FFF , 109px 1762px #FFF , 558px 255px #FFF , 719px 1820px #FFF , 588px 748px #FFF , 1899px 174px #FFF , 841px 1771px #FFF , 571px 1588px #FFF , 1155px 353px #FFF , 1879px 1220px #FFF , 1782px 870px #FFF , 407px 1238px #FFF , 1141px 63px #FFF , 1147px 1097px #FFF , 1406px 159px #FFF , 637px 1215px #FFF , 694px 1114px #FFF , 1536px 727px #FFF , 1708px 1512px #FFF , 1147px 880px #FFF , 684px 988px #FFF , 140px 851px #FFF , 1565px 1788px #FFF , 1573px 889px #FFF , 1172px 628px #FFF , 1474px 1978px #FFF , 435px 447px #FFF , 185px 1808px #FFF , 620px 1560px #FFF , 1387px 1196px #FFF , 138px 1854px #FFF , 137px 1499px #FFF , 1721px 1132px #FFF , 10px 32px #FFF , 1931px 1990px #FFF , 209px 91px #FFF , 1876px 1795px #FFF , 1130px 1551px #FFF , 284px 1848px #FFF , 389px 1603px #FFF , 612px 1121px #FFF , 825px 1926px #FFF , 161px 344px #FFF , 1729px 333px #FFF , 1037px 37px #FFF , 844px 1085px #FFF , 1179px 554px #FFF , 50px 478px #FFF , 1864px 704px #FFF , 233px 723px #FFF , 1202px 445px #FFF , 882px 189px #FFF , 362px 735px #FFF , 924px 411px #FFF , 902px 209px #FFF , 104px 185px #FFF , 1599px 1852px #FFF , 1974px 944px #FFF , 438px 1164px #FFF , 401px 1533px #FFF , 191px 1429px #FFF , 251px 1034px #FFF , 1807px 1412px #FFF , 72px 23px #FFF , 1752px 1146px #FFF , 261px 1481px #FFF , 548px 33px #FFF , 710px 1204px #FFF , 355px 1697px #FFF , 581px 100px #FFF , 318px 1146px #FFF , 929px 79px #FFF , 999px 347px #FFF , 155px 292px #FFF , 271px 677px #FFF , 920px 1596px #FFF , 1736px 184px #FFF , 1022px 1790px #FFF , 1465px 1762px #FFF , 820px 526px #FFF , 175px 37px #FFF , 440px 746px #FFF , 681px 1879px #FFF , 690px 1135px #FFF , 1960px 1453px #FFF , 422px 856px #FFF , 1217px 1232px #FFF , 1015px 1695px #FFF , 1933px 492px #FFF , 272px 448px #FFF , 1578px 1487px #FFF , 437px 874px #FFF , 947px 838px #FFF , 1339px 867px #FFF , 1484px 773px #FFF , 764px 66px #FFF , 418px 707px #FFF , 192px 1909px #FFF , 1629px 215px #FFF , 171px 260px #FFF , 1180px 220px #FFF , 488px 857px #FFF , 593px 493px #FFF , 1794px 886px #FFF , 1673px 1977px #FFF , 905px 1193px #FFF , 1372px 1843px #FFF , 1605px 908px #FFF , 659px 181px #FFF , 700px 1758px #FFF , 812px 1200px #FFF , 1800px 1440px #FFF , 1858px 212px #FFF , 628px 1026px #FFF , 1825px 1556px #FFF , 1641px 1750px #FFF , 1195px 1086px #FFF , 1465px 558px #FFF , 1634px 436px #FFF , 1354px 1831px #FFF , 1212px 1485px #FFF , 1491px 994px #FFF , 604px 1279px #FFF , 413px 1131px #FFF , 1677px 1086px #FFF , 841px 47px #FFF , 146px 489px #FFF , 117px 1195px #FFF , 67px 47px #FFF , 883px 258px #FFF , 1801px 1294px #FFF , 594px 1870px #FFF , 649px 531px #FFF , 721px 132px #FFF , 975px 1616px #FFF , 716px 94px #FFF , 295px 791px #FFF , 174px 1814px #FFF , 1130px 298px #FFF , 1747px 1835px #FFF , 605px 1521px #FFF , 78px 743px #FFF , 1685px 311px #FFF , 804px 341px #FFF , 1440px 852px #FFF , 1607px 1692px #FFF , 698px 1112px #FFF , 1153px 1608px #FFF , 539px 999px #FFF , 262px 353px #FFF , 457px 1246px #FFF , 1858px 998px #FFF , 364px 431px #FFF , 1907px 912px #FFF , 541px 916px #FFF , 168px 1384px #FFF , 357px 1321px #FFF , 1859px 1866px #FFF , 1001px 909px #FFF , 842px 1663px #FFF , 369px 1176px #FFF , 932px 1372px #FFF , 1606px 732px #FFF , 1844px 857px #FFF , 974px 1588px #FFF , 804px 1139px #FFF , 65px 1213px #FFF , 1066px 863px #FFF , 1991px 1734px #FFF , 300px 738px #FFF , 1260px 1141px #FFF , 83px 260px #FFF , 1219px 167px #FFF , 613px 990px #FFF , 873px 81px #FFF , 362px 235px #FFF , 373px 372px #FFF , 80px 247px #FFF , 902px 1141px #FFF , 294px 464px #FFF , 766px 1925px #FFF , 1151px 1305px #FFF , 1250px 1593px #FFF , 1289px 119px #FFF , 1525px 1505px #FFF , 234px 1306px #FFF , 571px 858px #FFF , 571px 996px #FFF , 766px 1342px #FFF , 1371px 716px #FFF , 711px 1939px #FFF , 904px 1797px #FFF , 424px 1710px #FFF , 762px 1614px #FFF , 1389px 1290px #FFF , 905px 689px #FFF , 352px 38px #FFF , 2000px 1317px #FFF , 597px 864px #FFF , 824px 711px #FFF , 966px 1060px #FFF , 958px 992px #FFF , 1121px 324px #FFF , 1624px 688px #FFF , 1737px 702px #FFF , 1566px 1344px #FFF , 697px 368px #FFF , 291px 1126px #FFF , 1732px 50px #FFF , 712px 1941px #FFF , 1257px 372px #FFF , 317px 1462px #FFF , 222px 309px #FFF , 1139px 647px #FFF , 170px 878px #FFF , 1272px 1511px #FFF , 1009px 1912px #FFF , 1875px 1105px #FFF , 1968px 1370px #FFF , 1193px 687px #FFF , 1498px 611px #FFF , 247px 1993px #FFF , 1686px 1611px #FFF , 937px 340px #FFF , 114px 1423px #FFF , 496px 1191px #FFF , 110px 1284px #FFF , 876px 687px #FFF , 1173px 214px #FFF , 210px 628px #FFF , 302px 1173px #FFF , 1318px 939px #FFF , 1665px 1310px #FFF , 66px 338px #FFF , 1355px 615px #FFF , 1139px 1672px #FFF , 91px 1000px #FFF , 112px 422px #FFF , 89px 503px #FFF , 97px 1599px #FFF , 1031px 1955px #FFF , 1755px 1532px #FFF , 1764px 1930px #FFF , 1822px 1751px #FFF , 133px 401px #FFF , 718px 85px #FFF , 1797px 78px #FFF , 520px 1725px #FFF , 226px 406px #FFF , 1561px 1574px #FFF , 340px 1602px #FFF , 718px 976px #FFF , 1823px 570px #FFF , 1298px 484px #FFF , 1023px 1903px #FFF , 1266px 1334px #FFF , 763px 877px #FFF , 223px 631px #FFF , 1761px 1293px #FFF , 878px 1px #FFF , 973px 696px #FFF , 975px 1841px #FFF , 1276px 302px #FFF , 1399px 1324px #FFF , 1706px 872px #FFF , 341px 1960px #FFF , 1384px 1655px #FFF , 1897px 767px #FFF , 68px 405px #FFF , 705px 310px #FFF , 194px 103px #FFF , 1432px 368px #FFF , 1262px 1682px #FFF , 1933px 1526px #FFF , 263px 655px #FFF , 1031px 1031px #FFF , 1557px 788px #FFF , 1558px 1360px #FFF , 812px 421px #FFF , 1951px 734px #FFF , 1567px 498px #FFF , 1832px 1229px #FFF , 913px 164px #FFF , 1907px 1273px #FFF , 533px 749px #FFF , 1235px 951px #FFF , 645px 1959px #FFF , 92px 1570px #FFF , 1169px 1434px #FFF , 118px 1223px #FFF , 583px 957px #FFF , 1245px 316px #FFF , 527px 863px #FFF , 372px 1007px #FFF , 244px 1251px #FFF , 314px 494px #FFF , 1842px 1463px #FFF , 1315px 730px #FFF , 1655px 1366px #FFF , 482px 979px #FFF , 340px 1808px #FFF , 256px 578px #FFF , 858px 1792px #FFF , 1965px 403px #FFF , 454px 253px #FFF , 1664px 698px #FFF , 1974px 750px #FFF , 262px 1801px #FFF , 1652px 1076px #FFF , 992px 711px #FFF , 1792px 1323px #FFF , 700px 1748px #FFF , 855px 966px #FFF , 1833px 1747px #FFF , 402px 1272px #FFF , 1391px 1039px #FFF , 1395px 1538px #FFF , 397px 1972px #FFF , 744px 1403px #FFF , 1784px 1046px #FFF , 111px 198px #FFF , 1827px 473px #FFF , 1347px 1891px #FFF , 1238px 1081px #FFF , 189px 908px #FFF , 1513px 542px #FFF , 673px 981px #FFF , 720px 1184px #FFF , 373px 792px #FFF , 1470px 1631px #FFF , 16px 822px #FFF , 1935px 829px #FFF , 364px 613px #FFF , 223px 899px #FFF , 1233px 874px #FFF , 1441px 1834px #FFF , 719px 894px #FFF , 76px 1610px #FFF , 296px 685px #FFF , 572px 1637px #FFF , 349px 114px #FFF , 1670px 1802px #FFF , 979px 928px #FFF , 1589px 574px #FFF , 756px 194px #FFF , 616px 507px #FFF , 271px 186px #FFF , 198px 360px #FFF , 1916px 418px #FFF , 721px 667px #FFF , 1937px 1908px #FFF , 17px 556px #FFF , 345px 443px #FFF , 718px 760px #FFF , 1922px 310px #FFF , 1185px 887px #FFF , 1745px 1848px #FFF , 909px 847px #FFF , 1170px 134px #FFF , 1773px 1133px #FFF , 1099px 233px #FFF , 1122px 1524px #FFF , 866px 907px #FFF , 398px 213px #FFF , 1287px 886px #FFF , 1194px 149px #FFF , 1876px 1667px #FFF , 332px 1658px #FFF , 146px 1253px #FFF , 958px 211px #FFF , 643px 47px #FFF , 1213px 1339px #FFF , 1637px 1939px #FFF , 1601px 355px #FFF , 256px 1982px #FFF , 989px 1609px #FFF , 1179px 701px #FFF , 685px 1463px #FFF , 1910px 465px #FFF , 764px 1930px #FFF , 1856px 433px #FFF , 720px 367px #FFF , 1821px 416px #FFF , 48px 1114px #FFF , 716px 489px #FFF , 174px 1972px #FFF , 115px 1373px #FFF , 1487px 141px #FFF , 1919px 1362px #FFF , 1662px 859px #FFF , 1168px 490px #FFF , 706px 1820px #FFF , 588px 318px #FFF , 107px 778px #FFF , 621px 1667px #FFF , 1331px 1996px #FFF , 1404px 1154px #FFF , 860px 1019px #FFF , 1385px 1883px #FFF , 1066px 1951px #FFF , 752px 444px #FFF , 955px 1031px #FFF , 1256px 1899px #FFF , 961px 1455px #FFF , 1101px 84px #FFF , 890px 335px #FFF , 798px 40px #FFF , 138px 54px #FFF , 1934px 252px #FFF , 429px 324px #FFF , 1645px 1522px #FFF , 218px 737px #FFF , 1625px 531px #FFF , 605px 1290px #FFF , 1867px 648px #FFF , 82px 1137px #FFF , 231px 1423px #FFF , 471px 944px #FFF , 1363px 1752px #FFF , 482px 1364px #FFF , 1305px 627px #FFF , 1065px 891px #FFF , 217px 1841px #FFF , 1843px 1501px #FFF , 1681px 734px #FFF , 185px 856px #FFF , 609px 1094px #FFF , 49px 1657px #FFF , 783px 594px #FFF , 1018px 1123px #FFF , 644px 1149px #FFF , 739px 1262px #FFF , 1439px 1187px #FFF , 1789px 1507px #FFF , 941px 791px #FFF , 1319px 1308px #FFF , 498px 626px #FFF , 1594px 858px #FFF , 783px 71px #FFF , 576px 1976px #FFF , 1625px 696px #FFF , 1821px 352px #FFF , 1039px 885px #FFF , 208px 430px #FFF , 124px 198px #FFF , 1964px 686px #FFF , 1440px 1952px #FFF , 231px 1435px #FFF , 1846px 853px #FFF , 1174px 536px #FFF , 1228px 310px #FFF , 1380px 699px #FFF , 1116px 169px #FFF , 1416px 1007px #FFF , 178px 192px #FFF , 1302px 1903px #FFF , 1892px 154px #FFF , 962px 1032px #FFF , 1009px 1916px #FFF , 1549px 1206px #FFF , 899px 968px #FFF , 902px 543px #FFF , 1516px 542px #FFF , 965px 527px #FFF , 1594px 696px #FFF , 856px 1719px #FFF , 1522px 248px #FFF , 1795px 283px #FFF , 1144px 946px #FFF , 1365px 199px #FFF , 359px 1347px #FFF , 1506px 263px #FFF , 433px 1793px #FFF , 201px 247px #FFF , 942px 838px #FFF , 1122px 1065px #FFF , 1997px 108px #FFF , 306px 989px #FFF , 641px 1713px #FFF , 1072px 959px #FFF , 1874px 1079px #FFF , 1938px 269px #FFF , 891px 389px #FFF , 22px 574px #FFF , 727px 474px #FFF , 1671px 1649px #FFF , 98px 400px #FFF , 641px 798px #FFF , 1218px 1051px #FFF , 907px 1485px #FFF , 1002px 1549px #FFF , 1932px 1448px #FFF , 1132px 573px #FFF , 1222px 1147px #FFF , 1009px 451px #FFF , 698px 1940px #FFF , 97px 1123px #FFF , 904px 751px #FFF , 1904px 593px #FFF , 1451px 1658px #FFF , 191px 1606px #FFF , 1346px 482px #FFF , 1935px 1086px #FFF , 1052px 224px #FFF , 526px 1810px #FFF , 1607px 606px #FFF , 427px 1830px #FFF , 1546px 407px #FFF , 1771px 208px #FFF , 1714px 181px #FFF , 1332px 943px #FFF , 1663px 1094px #FFF , 1861px 1747px #FFF , 1429px 1217px #FFF , 1733px 1915px #FFF , 925px 1179px #FFF , 735px 781px #FFF , 1775px 1989px #FFF , 1770px 476px #FFF , 844px 400px #FFF , 1793px 1517px #FFF , 544px 281px #FFF , 725px 344px #FFF , 1274px 764px #FFF , 1845px 339px #FFF , 582px 1745px #FFF , 351px 1287px #FFF , 207px 749px #FFF , 1063px 1411px #FFF , 1246px 342px #FFF , 1538px 166px #FFF , 770px 602px #FFF , 1214px 1971px #FFF , 113px 294px #FFF , 1157px 101px #FFF , 1657px 517px #FFF , 637px 1693px #FFF , 961px 1649px #FFF , 1754px 1572px #FFF , 1885px 659px #FFF , 238px 34px #FFF , 413px 1027px #FFF , 1709px 1556px #FFF , 460px 878px #FFF , 1597px 608px #FFF , 544px 434px #FFF , 1258px 477px #FFF , 565px 1863px #FFF , 426px 322px #FFF , 1917px 850px #FFF , 296px 144px #FFF , 643px 1896px #FFF , 511px 116px #FFF , 359px 847px #FFF , 702px 1133px #FFF , 857px 1371px #FFF , 559px 1758px #FFF , 1615px 1223px #FFF , 1927px 1736px #FFF , 704px 941px #FFF , 1932px 942px #FFF , 1462px 335px #FFF , 154px 1915px #FFF , 1387px 918px #FFF , 1512px 1041px #FFF , 1094px 1334px #FFF , 1678px 865px #FFF , 1960px 431px #FFF , 666px 1258px #FFF , 422px 1215px #FFF , 345px 802px #FFF , 1207px 647px #FFF , 1701px 374px #FFF , 1440px 1925px #FFF , 1536px 1163px #FFF , 905px 155px #FFF , 843px 1036px #FFF , 660px 823px #FFF , 1329px 661px #FFF , 1867px 899px #FFF , 1022px 514px #FFF , 1062px 1570px #FFF , 888px 1786px #FFF , 699px 1738px #FFF , 1831px 1712px #FFF , 434px 18px #FFF , 227px 205px #FFF , 520px 1279px #FFF , 1329px 764px #FFF , 1824px 47px #FFF , 112px 266px #FFF , 830px 1140px #FFF , 478px 637px #FFF , 634px 850px #FFF , 711px 873px #FFF , 987px 249px #FFF , 1454px 909px #FFF , 699px 922px #FFF , 1458px 1142px #FFF , 701px 1893px #FFF , 134px 384px #FFF , 904px 354px #FFF , 1913px 1229px #FFF , 1606px 1336px #FFF , 976px 1776px #FFF , 1726px 605px #FFF , 1244px 590px #FFF , 1351px 526px #FFF , 1997px 130px #FFF , 1137px 1134px #FFF , 1293px 283px #FFF , 977px 1608px #FFF , 422px 1252px #FFF , 236px 1653px #FFF , 28px 1722px #FFF , 698px 39px #FFF , 5px 434px #FFF , 1430px 1466px #FFF , 1470px 1596px #FFF , 487px 81px #FFF , 186px 340px #FFF , 1941px 1px #FFF , 1342px 487px #FFF , 813px 1855px #FFF , 1445px 148px #FFF , 1965px 1428px #FFF , 1122px 1277px #FFF , 846px 820px #FFF , 1804px 228px #FFF , 1501px 121px #FFF , 215px 1033px #FFF , 244px 426px #FFF , 976px 453px #FFF , 566px 953px #FFF , 1772px 213px #FFF , 1323px 1778px #FFF , 1350px 817px #FFF , 803px 913px #FFF , 1395px 1359px #FFF , 1995px 119px #FFF , 579px 1963px #FFF , 862px 1621px #FFF , 1718px 825px #FFF , 823px 27px #FFF , 1252px 41px #FFF , 1562px 835px #FFF , 1730px 633px #FFF , 1723px 1939px #FFF , 524px 1824px #FFF , 1921px 1450px #FFF , 1174px 1062px #FFF , 1008px 1932px #FFF , 467px 334px #FFF , 80px 818px #FFF , 1266px 1185px #FFF , 1589px 807px #FFF , 1221px 320px #FFF , 1724px 852px #FFF , 1194px 286px #FFF , 800px 1835px #FFF , 1958px 728px #FFF , 1271px 376px #FFF , 43px 1654px #FFF , 77px 803px #FFF , 1399px 197px #FFF , 591px 1743px #FFF , 652px 1925px #FFF , 107px 1939px #FFF , 1110px 1708px #FFF , 797px 1480px #FFF , 1516px 684px #FFF , 559px 1733px #FFF , 1265px 718px #FFF , 1263px 54px #FFF , 693px 113px #FFF , 1456px 1459px #FFF , 1527px 1324px #FFF; + animation: animStar 50s linear infinite; +} +#stars:after { + content: ""; + position: absolute; + top: 2000px; + width: 1px; + height: 1px; + background: transparent; + box-shadow: 1744px 122px #FFF , 134px 1321px #FFF , 92px 859px #FFF , 235px 1045px #FFF , 366px 912px #FFF , 491px 942px #FFF , 14px 1831px #FFF , 582px 476px #FFF , 588px 1230px #FFF , 1520px 1343px #FFF , 1671px 203px #FFF , 550px 341px #FFF , 1491px 549px #FFF , 558px 161px #FFF , 896px 1823px #FFF , 999px 1463px #FFF , 1557px 636px #FFF , 1754px 1307px #FFF , 1682px 1494px #FFF , 703px 1707px #FFF , 1945px 1847px #FFF , 1151px 1320px #FFF , 980px 144px #FFF , 478px 948px #FFF , 109px 1762px #FFF , 558px 255px #FFF , 719px 1820px #FFF , 588px 748px #FFF , 1899px 174px #FFF , 841px 1771px #FFF , 571px 1588px #FFF , 1155px 353px #FFF , 1879px 1220px #FFF , 1782px 870px #FFF , 407px 1238px #FFF , 1141px 63px #FFF , 1147px 1097px #FFF , 1406px 159px #FFF , 637px 1215px #FFF , 694px 1114px #FFF , 1536px 727px #FFF , 1708px 1512px #FFF , 1147px 880px #FFF , 684px 988px #FFF , 140px 851px #FFF , 1565px 1788px #FFF , 1573px 889px #FFF , 1172px 628px #FFF , 1474px 1978px #FFF , 435px 447px #FFF , 185px 1808px #FFF , 620px 1560px #FFF , 1387px 1196px #FFF , 138px 1854px #FFF , 137px 1499px #FFF , 1721px 1132px #FFF , 10px 32px #FFF , 1931px 1990px #FFF , 209px 91px #FFF , 1876px 1795px #FFF , 1130px 1551px #FFF , 284px 1848px #FFF , 389px 1603px #FFF , 612px 1121px #FFF , 825px 1926px #FFF , 161px 344px #FFF , 1729px 333px #FFF , 1037px 37px #FFF , 844px 1085px #FFF , 1179px 554px #FFF , 50px 478px #FFF , 1864px 704px #FFF , 233px 723px #FFF , 1202px 445px #FFF , 882px 189px #FFF , 362px 735px #FFF , 924px 411px #FFF , 902px 209px #FFF , 104px 185px #FFF , 1599px 1852px #FFF , 1974px 944px #FFF , 438px 1164px #FFF , 401px 1533px #FFF , 191px 1429px #FFF , 251px 1034px #FFF , 1807px 1412px #FFF , 72px 23px #FFF , 1752px 1146px #FFF , 261px 1481px #FFF , 548px 33px #FFF , 710px 1204px #FFF , 355px 1697px #FFF , 581px 100px #FFF , 318px 1146px #FFF , 929px 79px #FFF , 999px 347px #FFF , 155px 292px #FFF , 271px 677px #FFF , 920px 1596px #FFF , 1736px 184px #FFF , 1022px 1790px #FFF , 1465px 1762px #FFF , 820px 526px #FFF , 175px 37px #FFF , 440px 746px #FFF , 681px 1879px #FFF , 690px 1135px #FFF , 1960px 1453px #FFF , 422px 856px #FFF , 1217px 1232px #FFF , 1015px 1695px #FFF , 1933px 492px #FFF , 272px 448px #FFF , 1578px 1487px #FFF , 437px 874px #FFF , 947px 838px #FFF , 1339px 867px #FFF , 1484px 773px #FFF , 764px 66px #FFF , 418px 707px #FFF , 192px 1909px #FFF , 1629px 215px #FFF , 171px 260px #FFF , 1180px 220px #FFF , 488px 857px #FFF , 593px 493px #FFF , 1794px 886px #FFF , 1673px 1977px #FFF , 905px 1193px #FFF , 1372px 1843px #FFF , 1605px 908px #FFF , 659px 181px #FFF , 700px 1758px #FFF , 812px 1200px #FFF , 1800px 1440px #FFF , 1858px 212px #FFF , 628px 1026px #FFF , 1825px 1556px #FFF , 1641px 1750px #FFF , 1195px 1086px #FFF , 1465px 558px #FFF , 1634px 436px #FFF , 1354px 1831px #FFF , 1212px 1485px #FFF , 1491px 994px #FFF , 604px 1279px #FFF , 413px 1131px #FFF , 1677px 1086px #FFF , 841px 47px #FFF , 146px 489px #FFF , 117px 1195px #FFF , 67px 47px #FFF , 883px 258px #FFF , 1801px 1294px #FFF , 594px 1870px #FFF , 649px 531px #FFF , 721px 132px #FFF , 975px 1616px #FFF , 716px 94px #FFF , 295px 791px #FFF , 174px 1814px #FFF , 1130px 298px #FFF , 1747px 1835px #FFF , 605px 1521px #FFF , 78px 743px #FFF , 1685px 311px #FFF , 804px 341px #FFF , 1440px 852px #FFF , 1607px 1692px #FFF , 698px 1112px #FFF , 1153px 1608px #FFF , 539px 999px #FFF , 262px 353px #FFF , 457px 1246px #FFF , 1858px 998px #FFF , 364px 431px #FFF , 1907px 912px #FFF , 541px 916px #FFF , 168px 1384px #FFF , 357px 1321px #FFF , 1859px 1866px #FFF , 1001px 909px #FFF , 842px 1663px #FFF , 369px 1176px #FFF , 932px 1372px #FFF , 1606px 732px #FFF , 1844px 857px #FFF , 974px 1588px #FFF , 804px 1139px #FFF , 65px 1213px #FFF , 1066px 863px #FFF , 1991px 1734px #FFF , 300px 738px #FFF , 1260px 1141px #FFF , 83px 260px #FFF , 1219px 167px #FFF , 613px 990px #FFF , 873px 81px #FFF , 362px 235px #FFF , 373px 372px #FFF , 80px 247px #FFF , 902px 1141px #FFF , 294px 464px #FFF , 766px 1925px #FFF , 1151px 1305px #FFF , 1250px 1593px #FFF , 1289px 119px #FFF , 1525px 1505px #FFF , 234px 1306px #FFF , 571px 858px #FFF , 571px 996px #FFF , 766px 1342px #FFF , 1371px 716px #FFF , 711px 1939px #FFF , 904px 1797px #FFF , 424px 1710px #FFF , 762px 1614px #FFF , 1389px 1290px #FFF , 905px 689px #FFF , 352px 38px #FFF , 2000px 1317px #FFF , 597px 864px #FFF , 824px 711px #FFF , 966px 1060px #FFF , 958px 992px #FFF , 1121px 324px #FFF , 1624px 688px #FFF , 1737px 702px #FFF , 1566px 1344px #FFF , 697px 368px #FFF , 291px 1126px #FFF , 1732px 50px #FFF , 712px 1941px #FFF , 1257px 372px #FFF , 317px 1462px #FFF , 222px 309px #FFF , 1139px 647px #FFF , 170px 878px #FFF , 1272px 1511px #FFF , 1009px 1912px #FFF , 1875px 1105px #FFF , 1968px 1370px #FFF , 1193px 687px #FFF , 1498px 611px #FFF , 247px 1993px #FFF , 1686px 1611px #FFF , 937px 340px #FFF , 114px 1423px #FFF , 496px 1191px #FFF , 110px 1284px #FFF , 876px 687px #FFF , 1173px 214px #FFF , 210px 628px #FFF , 302px 1173px #FFF , 1318px 939px #FFF , 1665px 1310px #FFF , 66px 338px #FFF , 1355px 615px #FFF , 1139px 1672px #FFF , 91px 1000px #FFF , 112px 422px #FFF , 89px 503px #FFF , 97px 1599px #FFF , 1031px 1955px #FFF , 1755px 1532px #FFF , 1764px 1930px #FFF , 1822px 1751px #FFF , 133px 401px #FFF , 718px 85px #FFF , 1797px 78px #FFF , 520px 1725px #FFF , 226px 406px #FFF , 1561px 1574px #FFF , 340px 1602px #FFF , 718px 976px #FFF , 1823px 570px #FFF , 1298px 484px #FFF , 1023px 1903px #FFF , 1266px 1334px #FFF , 763px 877px #FFF , 223px 631px #FFF , 1761px 1293px #FFF , 878px 1px #FFF , 973px 696px #FFF , 975px 1841px #FFF , 1276px 302px #FFF , 1399px 1324px #FFF , 1706px 872px #FFF , 341px 1960px #FFF , 1384px 1655px #FFF , 1897px 767px #FFF , 68px 405px #FFF , 705px 310px #FFF , 194px 103px #FFF , 1432px 368px #FFF , 1262px 1682px #FFF , 1933px 1526px #FFF , 263px 655px #FFF , 1031px 1031px #FFF , 1557px 788px #FFF , 1558px 1360px #FFF , 812px 421px #FFF , 1951px 734px #FFF , 1567px 498px #FFF , 1832px 1229px #FFF , 913px 164px #FFF , 1907px 1273px #FFF , 533px 749px #FFF , 1235px 951px #FFF , 645px 1959px #FFF , 92px 1570px #FFF , 1169px 1434px #FFF , 118px 1223px #FFF , 583px 957px #FFF , 1245px 316px #FFF , 527px 863px #FFF , 372px 1007px #FFF , 244px 1251px #FFF , 314px 494px #FFF , 1842px 1463px #FFF , 1315px 730px #FFF , 1655px 1366px #FFF , 482px 979px #FFF , 340px 1808px #FFF , 256px 578px #FFF , 858px 1792px #FFF , 1965px 403px #FFF , 454px 253px #FFF , 1664px 698px #FFF , 1974px 750px #FFF , 262px 1801px #FFF , 1652px 1076px #FFF , 992px 711px #FFF , 1792px 1323px #FFF , 700px 1748px #FFF , 855px 966px #FFF , 1833px 1747px #FFF , 402px 1272px #FFF , 1391px 1039px #FFF , 1395px 1538px #FFF , 397px 1972px #FFF , 744px 1403px #FFF , 1784px 1046px #FFF , 111px 198px #FFF , 1827px 473px #FFF , 1347px 1891px #FFF , 1238px 1081px #FFF , 189px 908px #FFF , 1513px 542px #FFF , 673px 981px #FFF , 720px 1184px #FFF , 373px 792px #FFF , 1470px 1631px #FFF , 16px 822px #FFF , 1935px 829px #FFF , 364px 613px #FFF , 223px 899px #FFF , 1233px 874px #FFF , 1441px 1834px #FFF , 719px 894px #FFF , 76px 1610px #FFF , 296px 685px #FFF , 572px 1637px #FFF , 349px 114px #FFF , 1670px 1802px #FFF , 979px 928px #FFF , 1589px 574px #FFF , 756px 194px #FFF , 616px 507px #FFF , 271px 186px #FFF , 198px 360px #FFF , 1916px 418px #FFF , 721px 667px #FFF , 1937px 1908px #FFF , 17px 556px #FFF , 345px 443px #FFF , 718px 760px #FFF , 1922px 310px #FFF , 1185px 887px #FFF , 1745px 1848px #FFF , 909px 847px #FFF , 1170px 134px #FFF , 1773px 1133px #FFF , 1099px 233px #FFF , 1122px 1524px #FFF , 866px 907px #FFF , 398px 213px #FFF , 1287px 886px #FFF , 1194px 149px #FFF , 1876px 1667px #FFF , 332px 1658px #FFF , 146px 1253px #FFF , 958px 211px #FFF , 643px 47px #FFF , 1213px 1339px #FFF , 1637px 1939px #FFF , 1601px 355px #FFF , 256px 1982px #FFF , 989px 1609px #FFF , 1179px 701px #FFF , 685px 1463px #FFF , 1910px 465px #FFF , 764px 1930px #FFF , 1856px 433px #FFF , 720px 367px #FFF , 1821px 416px #FFF , 48px 1114px #FFF , 716px 489px #FFF , 174px 1972px #FFF , 115px 1373px #FFF , 1487px 141px #FFF , 1919px 1362px #FFF , 1662px 859px #FFF , 1168px 490px #FFF , 706px 1820px #FFF , 588px 318px #FFF , 107px 778px #FFF , 621px 1667px #FFF , 1331px 1996px #FFF , 1404px 1154px #FFF , 860px 1019px #FFF , 1385px 1883px #FFF , 1066px 1951px #FFF , 752px 444px #FFF , 955px 1031px #FFF , 1256px 1899px #FFF , 961px 1455px #FFF , 1101px 84px #FFF , 890px 335px #FFF , 798px 40px #FFF , 138px 54px #FFF , 1934px 252px #FFF , 429px 324px #FFF , 1645px 1522px #FFF , 218px 737px #FFF , 1625px 531px #FFF , 605px 1290px #FFF , 1867px 648px #FFF , 82px 1137px #FFF , 231px 1423px #FFF , 471px 944px #FFF , 1363px 1752px #FFF , 482px 1364px #FFF , 1305px 627px #FFF , 1065px 891px #FFF , 217px 1841px #FFF , 1843px 1501px #FFF , 1681px 734px #FFF , 185px 856px #FFF , 609px 1094px #FFF , 49px 1657px #FFF , 783px 594px #FFF , 1018px 1123px #FFF , 644px 1149px #FFF , 739px 1262px #FFF , 1439px 1187px #FFF , 1789px 1507px #FFF , 941px 791px #FFF , 1319px 1308px #FFF , 498px 626px #FFF , 1594px 858px #FFF , 783px 71px #FFF , 576px 1976px #FFF , 1625px 696px #FFF , 1821px 352px #FFF , 1039px 885px #FFF , 208px 430px #FFF , 124px 198px #FFF , 1964px 686px #FFF , 1440px 1952px #FFF , 231px 1435px #FFF , 1846px 853px #FFF , 1174px 536px #FFF , 1228px 310px #FFF , 1380px 699px #FFF , 1116px 169px #FFF , 1416px 1007px #FFF , 178px 192px #FFF , 1302px 1903px #FFF , 1892px 154px #FFF , 962px 1032px #FFF , 1009px 1916px #FFF , 1549px 1206px #FFF , 899px 968px #FFF , 902px 543px #FFF , 1516px 542px #FFF , 965px 527px #FFF , 1594px 696px #FFF , 856px 1719px #FFF , 1522px 248px #FFF , 1795px 283px #FFF , 1144px 946px #FFF , 1365px 199px #FFF , 359px 1347px #FFF , 1506px 263px #FFF , 433px 1793px #FFF , 201px 247px #FFF , 942px 838px #FFF , 1122px 1065px #FFF , 1997px 108px #FFF , 306px 989px #FFF , 641px 1713px #FFF , 1072px 959px #FFF , 1874px 1079px #FFF , 1938px 269px #FFF , 891px 389px #FFF , 22px 574px #FFF , 727px 474px #FFF , 1671px 1649px #FFF , 98px 400px #FFF , 641px 798px #FFF , 1218px 1051px #FFF , 907px 1485px #FFF , 1002px 1549px #FFF , 1932px 1448px #FFF , 1132px 573px #FFF , 1222px 1147px #FFF , 1009px 451px #FFF , 698px 1940px #FFF , 97px 1123px #FFF , 904px 751px #FFF , 1904px 593px #FFF , 1451px 1658px #FFF , 191px 1606px #FFF , 1346px 482px #FFF , 1935px 1086px #FFF , 1052px 224px #FFF , 526px 1810px #FFF , 1607px 606px #FFF , 427px 1830px #FFF , 1546px 407px #FFF , 1771px 208px #FFF , 1714px 181px #FFF , 1332px 943px #FFF , 1663px 1094px #FFF , 1861px 1747px #FFF , 1429px 1217px #FFF , 1733px 1915px #FFF , 925px 1179px #FFF , 735px 781px #FFF , 1775px 1989px #FFF , 1770px 476px #FFF , 844px 400px #FFF , 1793px 1517px #FFF , 544px 281px #FFF , 725px 344px #FFF , 1274px 764px #FFF , 1845px 339px #FFF , 582px 1745px #FFF , 351px 1287px #FFF , 207px 749px #FFF , 1063px 1411px #FFF , 1246px 342px #FFF , 1538px 166px #FFF , 770px 602px #FFF , 1214px 1971px #FFF , 113px 294px #FFF , 1157px 101px #FFF , 1657px 517px #FFF , 637px 1693px #FFF , 961px 1649px #FFF , 1754px 1572px #FFF , 1885px 659px #FFF , 238px 34px #FFF , 413px 1027px #FFF , 1709px 1556px #FFF , 460px 878px #FFF , 1597px 608px #FFF , 544px 434px #FFF , 1258px 477px #FFF , 565px 1863px #FFF , 426px 322px #FFF , 1917px 850px #FFF , 296px 144px #FFF , 643px 1896px #FFF , 511px 116px #FFF , 359px 847px #FFF , 702px 1133px #FFF , 857px 1371px #FFF , 559px 1758px #FFF , 1615px 1223px #FFF , 1927px 1736px #FFF , 704px 941px #FFF , 1932px 942px #FFF , 1462px 335px #FFF , 154px 1915px #FFF , 1387px 918px #FFF , 1512px 1041px #FFF , 1094px 1334px #FFF , 1678px 865px #FFF , 1960px 431px #FFF , 666px 1258px #FFF , 422px 1215px #FFF , 345px 802px #FFF , 1207px 647px #FFF , 1701px 374px #FFF , 1440px 1925px #FFF , 1536px 1163px #FFF , 905px 155px #FFF , 843px 1036px #FFF , 660px 823px #FFF , 1329px 661px #FFF , 1867px 899px #FFF , 1022px 514px #FFF , 1062px 1570px #FFF , 888px 1786px #FFF , 699px 1738px #FFF , 1831px 1712px #FFF , 434px 18px #FFF , 227px 205px #FFF , 520px 1279px #FFF , 1329px 764px #FFF , 1824px 47px #FFF , 112px 266px #FFF , 830px 1140px #FFF , 478px 637px #FFF , 634px 850px #FFF , 711px 873px #FFF , 987px 249px #FFF , 1454px 909px #FFF , 699px 922px #FFF , 1458px 1142px #FFF , 701px 1893px #FFF , 134px 384px #FFF , 904px 354px #FFF , 1913px 1229px #FFF , 1606px 1336px #FFF , 976px 1776px #FFF , 1726px 605px #FFF , 1244px 590px #FFF , 1351px 526px #FFF , 1997px 130px #FFF , 1137px 1134px #FFF , 1293px 283px #FFF , 977px 1608px #FFF , 422px 1252px #FFF , 236px 1653px #FFF , 28px 1722px #FFF , 698px 39px #FFF , 5px 434px #FFF , 1430px 1466px #FFF , 1470px 1596px #FFF , 487px 81px #FFF , 186px 340px #FFF , 1941px 1px #FFF , 1342px 487px #FFF , 813px 1855px #FFF , 1445px 148px #FFF , 1965px 1428px #FFF , 1122px 1277px #FFF , 846px 820px #FFF , 1804px 228px #FFF , 1501px 121px #FFF , 215px 1033px #FFF , 244px 426px #FFF , 976px 453px #FFF , 566px 953px #FFF , 1772px 213px #FFF , 1323px 1778px #FFF , 1350px 817px #FFF , 803px 913px #FFF , 1395px 1359px #FFF , 1995px 119px #FFF , 579px 1963px #FFF , 862px 1621px #FFF , 1718px 825px #FFF , 823px 27px #FFF , 1252px 41px #FFF , 1562px 835px #FFF , 1730px 633px #FFF , 1723px 1939px #FFF , 524px 1824px #FFF , 1921px 1450px #FFF , 1174px 1062px #FFF , 1008px 1932px #FFF , 467px 334px #FFF , 80px 818px #FFF , 1266px 1185px #FFF , 1589px 807px #FFF , 1221px 320px #FFF , 1724px 852px #FFF , 1194px 286px #FFF , 800px 1835px #FFF , 1958px 728px #FFF , 1271px 376px #FFF , 43px 1654px #FFF , 77px 803px #FFF , 1399px 197px #FFF , 591px 1743px #FFF , 652px 1925px #FFF , 107px 1939px #FFF , 1110px 1708px #FFF , 797px 1480px #FFF , 1516px 684px #FFF , 559px 1733px #FFF , 1265px 718px #FFF , 1263px 54px #FFF , 693px 113px #FFF , 1456px 1459px #FFF , 1527px 1324px #FFF; +} + +#stars2 { + width: 2px; + height: 2px; + background: transparent; + box-shadow: 1907px 1575px #FFF , 893px 268px #FFF , 1819px 666px #FFF , 366px 1985px #FFF , 1736px 1062px #FFF , 1124px 45px #FFF , 905px 1674px #FFF , 1570px 711px #FFF , 255px 1747px #FFF , 147px 1032px #FFF , 865px 1813px #FFF , 1721px 1461px #FFF , 202px 724px #FFF , 1860px 812px #FFF , 634px 1410px #FFF , 927px 1264px #FFF , 1648px 620px #FFF , 1915px 1309px #FFF , 731px 778px #FFF , 91px 1185px #FFF , 829px 1003px #FFF , 174px 1784px #FFF , 1094px 1874px #FFF , 1464px 484px #FFF , 1639px 1717px #FFF , 959px 573px #FFF , 1686px 1287px #FFF , 906px 356px #FFF , 970px 499px #FFF , 626px 890px #FFF , 1344px 1070px #FFF , 1351px 544px #FFF , 708px 68px #FFF , 1870px 130px #FFF , 556px 1270px #FFF , 1432px 618px #FFF , 769px 673px #FFF , 1289px 1410px #FFF , 1499px 1969px #FFF , 749px 1163px #FFF , 1198px 198px #FFF , 399px 133px #FFF , 1856px 1280px #FFF , 904px 194px #FFF , 973px 1107px #FFF , 1371px 1785px #FFF , 989px 1835px #FFF , 1043px 1517px #FFF , 787px 916px #FFF , 1635px 1155px #FFF , 752px 524px #FFF , 1926px 1279px #FFF , 1052px 1163px #FFF , 719px 1963px #FFF , 786px 519px #FFF , 1440px 500px #FFF , 156px 1265px #FFF , 1691px 429px #FFF , 1349px 1474px #FFF , 736px 459px #FFF , 248px 1678px #FFF , 1136px 510px #FFF , 1317px 10px #FFF , 1209px 1323px #FFF , 54px 469px #FFF , 730px 1939px #FFF , 960px 23px #FFF , 112px 941px #FFF , 1852px 1522px #FFF , 1993px 1972px #FFF , 265px 129px #FFF , 222px 1897px #FFF , 1766px 1804px #FFF , 1530px 1786px #FFF , 1045px 432px #FFF , 1916px 1980px #FFF , 309px 1780px #FFF , 1420px 559px #FFF , 1708px 103px #FFF , 324px 1407px #FFF , 1175px 943px #FFF , 80px 1221px #FFF , 1016px 1933px #FFF , 318px 560px #FFF , 190px 1489px #FFF , 1095px 892px #FFF , 1975px 1191px #FFF , 1197px 955px #FFF , 1482px 873px #FFF , 1912px 300px #FFF , 2000px 1636px #FFF , 1473px 1808px #FFF , 507px 192px #FFF , 924px 1300px #FFF , 1485px 1636px #FFF , 41px 1822px #FFF , 689px 120px #FFF , 769px 273px #FFF , 1039px 976px #FFF , 1057px 1520px #FFF , 1417px 1187px #FFF , 512px 1507px #FFF , 519px 45px #FFF , 1207px 1687px #FFF , 1824px 1488px #FFF , 1694px 31px #FFF , 1859px 52px #FFF , 1368px 268px #FFF , 190px 1404px #FFF , 940px 1003px #FFF , 167px 942px #FFF , 1641px 647px #FFF , 1051px 654px #FFF , 233px 1640px #FFF , 554px 511px #FFF , 1705px 1866px #FFF , 240px 1430px #FFF , 140px 668px #FFF , 648px 1617px #FFF , 252px 101px #FFF , 676px 1774px #FFF , 889px 1698px #FFF , 595px 853px #FFF , 249px 1768px #FFF , 1091px 1529px #FFF , 223px 839px #FFF , 239px 699px #FFF , 1547px 356px #FFF , 249px 1130px #FFF , 1209px 1946px #FFF , 1967px 1274px #FFF , 430px 298px #FFF , 1305px 134px #FFF , 156px 91px #FFF , 1712px 264px #FFF , 1256px 991px #FFF , 1887px 1844px #FFF , 1957px 1275px #FFF , 1718px 666px #FFF , 1090px 543px #FFF , 933px 1411px #FFF , 801px 323px #FFF , 202px 1659px #FFF , 1117px 549px #FFF , 290px 1859px #FFF , 1380px 1516px #FFF , 557px 1165px #FFF , 1953px 1758px #FFF , 1901px 1407px #FFF , 1144px 347px #FFF , 1640px 271px #FFF , 1996px 43px #FFF , 838px 488px #FFF , 1151px 1529px #FFF , 306px 460px #FFF , 1666px 635px #FFF , 1572px 633px #FFF , 1797px 1076px #FFF , 1727px 1119px #FFF , 474px 871px #FFF , 1491px 1398px #FFF , 1301px 868px #FFF , 1632px 454px #FFF , 1611px 466px #FFF , 498px 1162px #FFF , 796px 269px #FFF , 1988px 747px #FFF , 502px 12px #FFF , 276px 1260px #FFF , 1536px 974px #FFF , 956px 656px #FFF , 107px 701px #FFF , 965px 491px #FFF , 1646px 247px #FFF , 1515px 921px #FFF , 1813px 519px #FFF , 697px 143px #FFF , 591px 1452px #FFF , 1773px 1411px #FFF , 1622px 1401px #FFF , 534px 340px #FFF , 1590px 284px #FFF , 1464px 528px #FFF , 734px 1718px #FFF , 1929px 1683px #FFF , 656px 480px #FFF , 833px 705px #FFF , 1567px 109px #FFF , 1055px 330px #FFF , 1943px 1367px #FFF , 1935px 1512px #FFF , 355px 1024px #FFF , 1894px 218px #FFF , 1703px 1772px #FFF , 781px 1394px #FFF , 367px 42px #FFF , 100px 690px #FFF , 1831px 458px #FFF , 1884px 1878px #FFF , 814px 1013px #FFF; + animation: animStar 100s linear infinite; +} +#stars2:after { + content: ""; + position: absolute; + top: 2000px; + width: 2px; + height: 2px; + background: transparent; + box-shadow: 1907px 1575px #FFF , 893px 268px #FFF , 1819px 666px #FFF , 366px 1985px #FFF , 1736px 1062px #FFF , 1124px 45px #FFF , 905px 1674px #FFF , 1570px 711px #FFF , 255px 1747px #FFF , 147px 1032px #FFF , 865px 1813px #FFF , 1721px 1461px #FFF , 202px 724px #FFF , 1860px 812px #FFF , 634px 1410px #FFF , 927px 1264px #FFF , 1648px 620px #FFF , 1915px 1309px #FFF , 731px 778px #FFF , 91px 1185px #FFF , 829px 1003px #FFF , 174px 1784px #FFF , 1094px 1874px #FFF , 1464px 484px #FFF , 1639px 1717px #FFF , 959px 573px #FFF , 1686px 1287px #FFF , 906px 356px #FFF , 970px 499px #FFF , 626px 890px #FFF , 1344px 1070px #FFF , 1351px 544px #FFF , 708px 68px #FFF , 1870px 130px #FFF , 556px 1270px #FFF , 1432px 618px #FFF , 769px 673px #FFF , 1289px 1410px #FFF , 1499px 1969px #FFF , 749px 1163px #FFF , 1198px 198px #FFF , 399px 133px #FFF , 1856px 1280px #FFF , 904px 194px #FFF , 973px 1107px #FFF , 1371px 1785px #FFF , 989px 1835px #FFF , 1043px 1517px #FFF , 787px 916px #FFF , 1635px 1155px #FFF , 752px 524px #FFF , 1926px 1279px #FFF , 1052px 1163px #FFF , 719px 1963px #FFF , 786px 519px #FFF , 1440px 500px #FFF , 156px 1265px #FFF , 1691px 429px #FFF , 1349px 1474px #FFF , 736px 459px #FFF , 248px 1678px #FFF , 1136px 510px #FFF , 1317px 10px #FFF , 1209px 1323px #FFF , 54px 469px #FFF , 730px 1939px #FFF , 960px 23px #FFF , 112px 941px #FFF , 1852px 1522px #FFF , 1993px 1972px #FFF , 265px 129px #FFF , 222px 1897px #FFF , 1766px 1804px #FFF , 1530px 1786px #FFF , 1045px 432px #FFF , 1916px 1980px #FFF , 309px 1780px #FFF , 1420px 559px #FFF , 1708px 103px #FFF , 324px 1407px #FFF , 1175px 943px #FFF , 80px 1221px #FFF , 1016px 1933px #FFF , 318px 560px #FFF , 190px 1489px #FFF , 1095px 892px #FFF , 1975px 1191px #FFF , 1197px 955px #FFF , 1482px 873px #FFF , 1912px 300px #FFF , 2000px 1636px #FFF , 1473px 1808px #FFF , 507px 192px #FFF , 924px 1300px #FFF , 1485px 1636px #FFF , 41px 1822px #FFF , 689px 120px #FFF , 769px 273px #FFF , 1039px 976px #FFF , 1057px 1520px #FFF , 1417px 1187px #FFF , 512px 1507px #FFF , 519px 45px #FFF , 1207px 1687px #FFF , 1824px 1488px #FFF , 1694px 31px #FFF , 1859px 52px #FFF , 1368px 268px #FFF , 190px 1404px #FFF , 940px 1003px #FFF , 167px 942px #FFF , 1641px 647px #FFF , 1051px 654px #FFF , 233px 1640px #FFF , 554px 511px #FFF , 1705px 1866px #FFF , 240px 1430px #FFF , 140px 668px #FFF , 648px 1617px #FFF , 252px 101px #FFF , 676px 1774px #FFF , 889px 1698px #FFF , 595px 853px #FFF , 249px 1768px #FFF , 1091px 1529px #FFF , 223px 839px #FFF , 239px 699px #FFF , 1547px 356px #FFF , 249px 1130px #FFF , 1209px 1946px #FFF , 1967px 1274px #FFF , 430px 298px #FFF , 1305px 134px #FFF , 156px 91px #FFF , 1712px 264px #FFF , 1256px 991px #FFF , 1887px 1844px #FFF , 1957px 1275px #FFF , 1718px 666px #FFF , 1090px 543px #FFF , 933px 1411px #FFF , 801px 323px #FFF , 202px 1659px #FFF , 1117px 549px #FFF , 290px 1859px #FFF , 1380px 1516px #FFF , 557px 1165px #FFF , 1953px 1758px #FFF , 1901px 1407px #FFF , 1144px 347px #FFF , 1640px 271px #FFF , 1996px 43px #FFF , 838px 488px #FFF , 1151px 1529px #FFF , 306px 460px #FFF , 1666px 635px #FFF , 1572px 633px #FFF , 1797px 1076px #FFF , 1727px 1119px #FFF , 474px 871px #FFF , 1491px 1398px #FFF , 1301px 868px #FFF , 1632px 454px #FFF , 1611px 466px #FFF , 498px 1162px #FFF , 796px 269px #FFF , 1988px 747px #FFF , 502px 12px #FFF , 276px 1260px #FFF , 1536px 974px #FFF , 956px 656px #FFF , 107px 701px #FFF , 965px 491px #FFF , 1646px 247px #FFF , 1515px 921px #FFF , 1813px 519px #FFF , 697px 143px #FFF , 591px 1452px #FFF , 1773px 1411px #FFF , 1622px 1401px #FFF , 534px 340px #FFF , 1590px 284px #FFF , 1464px 528px #FFF , 734px 1718px #FFF , 1929px 1683px #FFF , 656px 480px #FFF , 833px 705px #FFF , 1567px 109px #FFF , 1055px 330px #FFF , 1943px 1367px #FFF , 1935px 1512px #FFF , 355px 1024px #FFF , 1894px 218px #FFF , 1703px 1772px #FFF , 781px 1394px #FFF , 367px 42px #FFF , 100px 690px #FFF , 1831px 458px #FFF , 1884px 1878px #FFF , 814px 1013px #FFF; +} + +#stars3 { + width: 3px; + height: 3px; + background: transparent; + box-shadow: 1994px 1692px #FFF , 961px 1928px #FFF , 819px 1320px #FFF , 1899px 52px #FFF , 28px 1937px #FFF , 157px 88px #FFF , 860px 1909px #FFF , 720px 427px #FFF , 1319px 1469px #FFF , 677px 960px #FFF , 1265px 1181px #FFF , 1176px 1361px #FFF , 1957px 753px #FFF , 1674px 1355px #FFF , 929px 1206px #FFF , 1038px 898px #FFF , 1229px 365px #FFF , 1085px 51px #FFF , 851px 650px #FFF , 385px 21px #FFF , 41px 1153px #FFF , 718px 70px #FFF , 1321px 579px #FFF , 497px 1458px #FFF , 1981px 813px #FFF , 776px 1187px #FFF , 1345px 31px #FFF , 1571px 400px #FFF , 339px 587px #FFF , 146px 750px #FFF , 64px 61px #FFF , 307px 981px #FFF , 388px 849px #FFF , 1398px 936px #FFF , 522px 765px #FFF , 1146px 350px #FFF , 19px 206px #FFF , 1767px 319px #FFF , 1203px 425px #FFF , 1917px 1018px #FFF , 91px 1401px #FFF , 898px 697px #FFF , 1712px 1121px #FFF , 633px 1119px #FFF , 137px 1266px #FFF , 1006px 931px #FFF , 1644px 1804px #FFF , 1596px 1057px #FFF , 1298px 543px #FFF , 1505px 996px #FFF , 1972px 1383px #FFF , 1210px 1497px #FFF , 804px 1840px #FFF , 913px 1047px #FFF , 187px 1824px #FFF , 1564px 1994px #FFF , 557px 1737px #FFF , 508px 1609px #FFF , 1259px 1911px #FFF , 1294px 1381px #FFF , 1845px 1843px #FFF , 667px 1497px #FFF , 1046px 945px #FFF , 937px 1889px #FFF , 982px 1806px #FFF , 1293px 671px #FFF , 668px 904px #FFF , 358px 1971px #FFF , 133px 766px #FFF , 1152px 1573px #FFF , 318px 694px #FFF , 578px 1184px #FFF , 1620px 1701px #FFF , 1359px 354px #FFF , 1807px 1367px #FFF , 458px 911px #FFF , 1387px 806px #FFF , 523px 81px #FFF , 1243px 341px #FFF , 906px 1730px #FFF , 1629px 474px #FFF , 1690px 419px #FFF , 847px 808px #FFF , 528px 1627px #FFF , 480px 718px #FFF , 537px 593px #FFF , 1432px 1333px #FFF , 200px 1228px #FFF , 1800px 1375px #FFF , 725px 1231px #FFF , 1749px 1432px #FFF , 1948px 303px #FFF , 1889px 252px #FFF , 1114px 1400px #FFF , 759px 646px #FFF , 222px 571px #FFF , 1908px 1401px #FFF , 1856px 1204px #FFF , 338px 1645px #FFF , 1528px 1050px #FFF; + animation: animStar 150s linear infinite; +} +#stars3:after { + content: ""; + position: absolute; + top: 2000px; + background: transparent; + box-shadow: 1994px 1692px #FFF , 961px 1928px #FFF , 819px 1320px #FFF , 1899px 52px #FFF , 28px 1937px #FFF , 157px 88px #FFF , 860px 1909px #FFF , 720px 427px #FFF , 1319px 1469px #FFF , 677px 960px #FFF , 1265px 1181px #FFF , 1176px 1361px #FFF , 1957px 753px #FFF , 1674px 1355px #FFF , 929px 1206px #FFF , 1038px 898px #FFF , 1229px 365px #FFF , 1085px 51px #FFF , 851px 650px #FFF , 385px 21px #FFF , 41px 1153px #FFF , 718px 70px #FFF , 1321px 579px #FFF , 497px 1458px #FFF , 1981px 813px #FFF , 776px 1187px #FFF , 1345px 31px #FFF , 1571px 400px #FFF , 339px 587px #FFF , 146px 750px #FFF , 64px 61px #FFF , 307px 981px #FFF , 388px 849px #FFF , 1398px 936px #FFF , 522px 765px #FFF , 1146px 350px #FFF , 19px 206px #FFF , 1767px 319px #FFF , 1203px 425px #FFF , 1917px 1018px #FFF , 91px 1401px #FFF , 898px 697px #FFF , 1712px 1121px #FFF , 633px 1119px #FFF , 137px 1266px #FFF , 1006px 931px #FFF , 1644px 1804px #FFF , 1596px 1057px #FFF , 1298px 543px #FFF , 1505px 996px #FFF , 1972px 1383px #FFF , 1210px 1497px #FFF , 804px 1840px #FFF , 913px 1047px #FFF , 187px 1824px #FFF , 1564px 1994px #FFF , 557px 1737px #FFF , 508px 1609px #FFF , 1259px 1911px #FFF , 1294px 1381px #FFF , 1845px 1843px #FFF , 667px 1497px #FFF , 1046px 945px #FFF , 937px 1889px #FFF , 982px 1806px #FFF , 1293px 671px #FFF , 668px 904px #FFF , 358px 1971px #FFF , 133px 766px #FFF , 1152px 1573px #FFF , 318px 694px #FFF , 578px 1184px #FFF , 1620px 1701px #FFF , 1359px 354px #FFF , 1807px 1367px #FFF , 458px 911px #FFF , 1387px 806px #FFF , 523px 81px #FFF , 1243px 341px #FFF , 906px 1730px #FFF , 1629px 474px #FFF , 1690px 419px #FFF , 847px 808px #FFF , 528px 1627px #FFF , 480px 718px #FFF , 537px 593px #FFF , 1432px 1333px #FFF , 200px 1228px #FFF , 1800px 1375px #FFF , 725px 1231px #FFF , 1749px 1432px #FFF , 1948px 303px #FFF , 1889px 252px #FFF , 1114px 1400px #FFF , 759px 646px #FFF , 222px 571px #FFF , 1908px 1401px #FFF , 1856px 1204px #FFF , 338px 1645px #FFF , 1528px 1050px #FFF; +} + +@keyframes animStar { + from { + transform: translateY(0px); + } + to { + transform: translateY(-2000px); + } +} 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..ae7c087910 --- /dev/null +++ b/app/assets/stylesheets/foundation_and_overrides.scss @@ -0,0 +1,56 @@ +@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; +@import 'motion-ui/motion-ui'; +@include motion-ui-transitions; +@include motion-ui-animations; diff --git a/app/assets/stylesheets/merchants.scss b/app/assets/stylesheets/merchants.scss new file mode 100644 index 0000000000..f4c164d600 --- /dev/null +++ b/app/assets/stylesheets/merchants.scss @@ -0,0 +1,3 @@ +// 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/ 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/products.scss b/app/assets/stylesheets/products.scss new file mode 100644 index 0000000000..bff386e55a --- /dev/null +++ b/app/assets/stylesheets/products.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Products 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..7bef9cf826 --- /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..c10da2d0fa --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,21 @@ +class ApplicationController < ActionController::Base + protect_from_forgery with: :exception + + def create_order + @order = Order.new + @order.status = "pending" + + if @order.save + session[:order_id] = @order.id + flash[:status] = :success + else + flash[:status] = :failure + flash[:result_text] = "Could not initialize pending order." + end + end + + def current_user + @current_user ||= Merchant.find_by(id: session[:user_id]) + + end +end diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb new file mode 100644 index 0000000000..9f20043950 --- /dev/null +++ b/app/controllers/categories_controller.rb @@ -0,0 +1,53 @@ +class CategoriesController < ApplicationController + before_action :find_category, only: [:show, :destroy] + + def index + @categories = Category.all + end + + def new + @category = Category.new + end + + def create + @category = Category.new(name: params[:category][:name]) + if @category.save + flash[:status] = :success + flash[:result_text] = "Successfully created #{@category.name} category" + redirect_to category_path(@category.id) + else + flash[:status] = :failure + flash[:result_text] = "Could not create #{@category.name} category." + flash[:messages] = @category.errors.messages + render :new, status: :bad_request + end + end + + def show + if @category == nil + flash[:status] = :failure + flash[:result_text] = "That category does not exist." + redirect_to categories_path, status: :not_found + end + end + + def destroy + if !@category + redirect_to root_path, status: :not_found + elsif @category.destroy + flash[:status] = :success + flash[:result_text] = "Category deleted" + redirect_to categories_path + else + flash[:status] = :failure + flash[:result_text] = "That category is unable to be deleted." + end + end + + private + + def find_category + @category = Category.find_by(id: params[:id]) + 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/merchants_controller.rb b/app/controllers/merchants_controller.rb new file mode 100644 index 0000000000..d48f87e3c6 --- /dev/null +++ b/app/controllers/merchants_controller.rb @@ -0,0 +1,53 @@ +class MerchantsController < ApplicationController + before_action :find_merchant, only: [:show, :edit, :update, :destroy] + + def index + @merchants = Merchant.all + end + + def new + @merchant = Merchant.new + end + + def show + if @merchant == nil + flash[:status] = :failure + flash[:result_text] = "That merchant does not exist." + redirect_to merchants_path, status: :not_found + end + end + + # def edit + # unless @merchant + # flash[:status] = :failure + # flash[:result_text] = "That merchant could not be found." + # end + # end + + # def update + # redirect_to merchants_path unless @merchant + # redirect_to root_path unless @merchant + # + # if @merchant.update_attributes merchant_params + # flash[:status] = :success + # flash[:result_text] = "Successfully updated merchant details!" + # redirect_to merchant_path(@merchant.id) + # else + # render :edit + # end + # end + + # def destroy + # find_merchant + # redirect_to root_path + # end + + private + def merchant_params + return params.require(:merchant).permit(:username, :email) + end + + def find_merchant + @merchant = Merchant.find_by(id: params[:id].to_i) + end +end diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb new file mode 100644 index 0000000000..feda2a79ae --- /dev/null +++ b/app/controllers/orders_controller.rb @@ -0,0 +1,127 @@ +class OrdersController < ApplicationController + before_action :find_order, only: [:show, :edit, :update] + before_action :find_merchant, only: [:index] + + def index + if current_user != @merchant + flash[:result_text] = "You cannot view this page" + return redirect_to home_path + end + if params[:status] == "pending" + @merch_orders = Order.joins(:products).where({ "products.merchant_id" => session[:user_id]}).select("orders.*", "products.name as product_name", "products.price as product_price", "products.id as product_id") + + @merch_orders = @merch_orders.where(:status => "pending") + + elsif params[:status] == "complete" + @merch_orders = Order.joins(:products).where({ "products.merchant_id" => session[:user_id] }).select("orders.*", "products.name as product_name", "products.price as product_price", "products.id as product_id") + + @merch_orders = @merch_orders.where(:status => "complete") + + elsif params[:status] == "shipped" + @merch_orders = Order.joins(:products).where({ "products.merchant_id" => session[:user_id] }).select("orders.*", "products.name as product_name", "products.price as product_price", "products.id as product_id") + + @merch_orders = @merch_orders.where(:status => "shipped") + + else + @merch_orders = Order.joins(:products).where({ "products.merchant_id" => session[:user_id] }).select("orders.*", "products.name as product_name", "products.price as product_price", "products.id as product_id") + end + end + + def show + unless @order + redirect_to root_path, status: :not_found + end + end + + def new + @order = Order.new + end + + def create + create_order + render :show + #see application controller + end + + def edit + if !@order + redirect_to root_path, status: :not_found + elsif @order + if @order.status == "shipped" + flash[:result_text] = "You cannot edit a shipped order" + redirect_to home_path + end + end + end + + def update + if !@order + redirect_to root_path, status: :not_found + elsif @order + if @order.status == "shipped" + flash[:status] = :failure + flash[:result_text] = "You cannot update a shipped order" + redirect_to home_path + else + @order.status = "complete" + if @order.update_attributes order_params + # @order.status = "complete" + @order.save + flash[:status] = :success + flash[:result_text] = "You have successfully submitted your order!" + session[:order_id] = nil + redirect_to order_confirm_order_path(@order.id) + else + + # flash[:result_text] = "All fields are required to complete your order." + error = "Please correct the following fields: " + @order.errors.messages.each do |field, message| + error << "- #{field.capitalize} " + end + flash[:status] = :failure + flash[:result_text] = error + render :edit, status: :bad_request + end + end + end + end + + def shipped + @order = Order.find_by(id: params[:id]) + if @order.status == "complete" + @order.status = "shipped" + if @order.save + flash[:status] = :success + flash[:result_text] = "You have successfully shipped your order!" + redirect_back fallback_location: root_path + params[:id] = nil + else + flash[:status] = :failure + flash[:result_text] = "Couldn't mark as shipped." + end + else + flash[:status] = :failure + flash[:result_text] = "Shipping not allowed for this order" + redirect_to home_path + end + end + + def individual_order + @order = Order.find_by(id: params[:id]) + end + + private + + def order_params + return params.require(:order).permit(:status, :name, :address, :city, :state, :zip_code, :email, :card_number, :card_exp, :card_cvv) + end + + def find_order + @order = Order.find_by(id: session[:order_id]) + end + + def find_merchant + @merchant = Merchant.find_by(id: params[:merchant_id]) + end + +end diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb new file mode 100644 index 0000000000..3ca52ffe33 --- /dev/null +++ b/app/controllers/products_controller.rb @@ -0,0 +1,162 @@ +class ProductsController < ApplicationController + before_action :find_product, only: [:show, :update, :destroy, :add_product_to_cart, :remove_product_from_cart] + + def index + if params[:merchant_id] + @merchant = Merchant.find_by(id: params[:merchant_id]) + if @merchant == nil + flash[:status] = :failure + flash[:result_text] = "Products for that merchant ID could not be found" + redirect_to products_path, status: :not_found + elsif @merchant.id == session[:user_id] + @products = @merchant.products + else + @products = @merchant.products.where(available: "Available") + end + # elsif + # params[:review_id] + # @products = Review.where(product_id: params[:category_id]) + # if @products == nil + # flash[:status] = :failure + # flash[:result_text] = "Products for that review ID could not be found" + # redirect_to products_path, status: :not_found + # end + elsif + params[:category_id] + @category = Category.find_by(id: params[:category_id]) + if @category == nil + flash[:status] = :failure + flash[:result_text] = "Products for that category could not be found" + redirect_to products_path, status: :not_found + else + @products = @category.products.where(available: "Available") + end + else + @products = Product.all.where(available: "Available") + end + end + + def new + @product = Product.new + end + + def create + @product = Product.new product_params + @product.merchant_id = session[:user_id] + if @product.save + flash[:status] = :success + flash[:result_text] = "Successfully created your product!" + redirect_to product_path(@product.id) + else + flash[:status] = :failure + flash[:result_text] = "Could not create #{@product.name}." + flash[:messages] = @product.errors.messages + render :new, status: :bad_request + end + end + + def show + find_product + if @product == nil || @product.available == "Retired" + flash[:status] = :failure + flash[:result_text] = "That product is not available for viewing." + redirect_to products_path, status: :not_found + end + end + + def edit + @product = Product.find_by(id: params[:id]) + unless @product + flash[:status] = :failure + flash[:result_text] = "That product could not be found." + end + end + + def update + if !@product + redirect_to root_path, status: :not_found + end + + category = Category.where(name: params[:product][:categories]) + @product.categories << category + @product.save + + if @product.update_attributes product_params + flash[:status] = :success + flash[:result_text] = "Successfully updated product details!" + redirect_to merchant_products_path(session[:user_id]) + else + render :edit + end + end + + def destroy + if !@product + redirect_to root_path, status: :not_found + elsif @product.destroy + flash[:status] = :success + flash[:result_text] = "Product deleted" + redirect_to products_path + else + flash[:status] = :failure + flash[:result_text] = "That product is unable to be deleted." + redirect_to products_path, status: :not_found + end + end + + def add_product_to_cart + @product = Product.find_by(id: params[:id]) + if @product.remove_one_from_stock + if Order.find_by(id: session[:order_id]) == nil + create_order + order = Order.find_by(id: session[:order_id]) + order.products << @product + order.save + flash[:status] = :success + flash[:result_text] = "product added to cart" + redirect_to order_path(order.id) + else + order = Order.find_by(id: session[:order_id]) + order.products << @product + order.save + flash[:status] = :success + flash[:result_text] = "product added to cart" + redirect_to order_path(order.id) + end + else + flash[:status] = :failure + flash[:result_text] = "Product not available" + redirect_back(fallback_location: products_path) + # status :bad_request + end + end + def remove_product_from_cart + @product = Product.find_by(id: params[:id]) + order = Order.find_by(id: session[:order_id]) + if @product && order + index_of_first_found = order.products.index {|element| element.id == @product.id} + if index_of_first_found + orders_products_array = order.products.to_a + orders_products_array.delete_at(index_of_first_found) + order.products.replace([]) + order.products.replace(orders_products_array) + @product.add_one_to_stock + flash[:status] = :success + flash[:result_text] = "Successfully removed product from cart" + redirect_to order_path(order.id) + else + flash[:status] = :failure + flash[:result_text] = "Error: Product not found in cart" + end + end + end + +private + def product_params + params.require(:product).permit(:name, :price, :quantity_avail, :available, :photo, :description) + end + + def find_product + @product = Product.find_by(id: params[:id]) + end +end diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb new file mode 100644 index 0000000000..4ff75d8bda --- /dev/null +++ b/app/controllers/reviews_controller.rb @@ -0,0 +1,49 @@ +class ReviewsController < ApplicationController + + + def new + @product = Product.find_by(id: params[:product_id]) + @review = Review.new + end + + def create + @product = Product.find_by(id: params[:product_id]) + + if current_user && owner? + flash[:result_text] = "You cannot review your own product" + return redirect_to home_path + end + @review = Review.new(review_params) + @review.product_id = params[:product_id] + # @review.rating = @review.rating.to_i + + if @review.save + flash[:status] = :success + flash[:result_text] = "Successfully reviewed!" + # redirect_to root_path + redirect_to product_path(@review.product_id) + else + + puts "the new model" + puts @review + puts @review.rating + puts @review.text_review + flash[:status] = :failure + flash[:result_text] = "Could not review this product." + flash[:messages] = @review.errors.messages + render :new, status: :bad_request + end + end + + + private + + def owner? + return session[:user_id] == @product.merchant.id ? true : false + end + + + def review_params + params.require(:review).permit(:rating, :text_review) + end +end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb new file mode 100644 index 0000000000..83a3676e24 --- /dev/null +++ b/app/controllers/sessions_controller.rb @@ -0,0 +1,31 @@ +class SessionsController < ApplicationController + def create + @auth_hash = request.env['omniauth.auth'] + + @merchant = Merchant.find_by(uid: @auth_hash['uid'], provider: @auth_hash['provider']) + + if @merchant + session[:user_id] = @merchant.id + flash[:result_text] = "Welcome back #{@merchant.username}" + else + @merchant = Merchant.new(uid: @auth_hash['uid'], provider: @auth_hash['provider'], username: @auth_hash['info']['nickname'], email: @auth_hash['info']['email']) + if @merchant.save + session[:user_id] = @merchant.id + flash[:status] = :success + flash[:result_text] = "Welcome to Sourceress, #{@merchant.username}" + else + flash[:result_text] = "Unable to save user!" + end + end + redirect_to home_path + end + +def logout + session[:user_id] = nil + session[:order_id] = nil + flash[:status] = :success + flash[:result_text] = "Successfully logged out!" + redirect_to home_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/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/products_helper.rb b/app/helpers/products_helper.rb new file mode 100644 index 0000000000..ab5c42b325 --- /dev/null +++ b/app/helpers/products_helper.rb @@ -0,0 +1,2 @@ +module ProductsHelper +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..f47c9aa0c8 --- /dev/null +++ b/app/models/category.rb @@ -0,0 +1,5 @@ +class Category < ApplicationRecord + has_and_belongs_to_many :products, dependent: :destroy + + validates :name, presence: true, uniqueness: true, length: { maximum: 25 } +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/merchant.rb b/app/models/merchant.rb new file mode 100644 index 0000000000..2495ea8599 --- /dev/null +++ b/app/models/merchant.rb @@ -0,0 +1,9 @@ +class Merchant < ApplicationRecord + has_many :products + + has_attached_file :photo, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png" + validates_attachment_content_type :photo, content_type: /\Aimage\/.*\z/ + + validates :username, presence: true, uniqueness: true + validates :email, presence: true, uniqueness: true +end diff --git a/app/models/order.rb b/app/models/order.rb new file mode 100644 index 0000000000..32391faf65 --- /dev/null +++ b/app/models/order.rb @@ -0,0 +1,43 @@ +class Order < ApplicationRecord + VALID_STATS = ["pending", "complete", "shipped"] + has_and_belongs_to_many :products + validates :status, presence: true, inclusion: { in: VALID_STATS } + validates :name, presence: true, if: :completed? + validates :address, presence: true, if: :completed? + validates :city, presence: true, if: :completed? + validates :state, presence: true, if: :completed? + validates :email, presence: true, if: :completed?, format: { with: /\A(\S+)@(.+)\.(\S+)\z/ } + validates :card_number, presence: true, if: :completed?, numericality: true, length: {is: 16} + validates :card_exp, presence: true, if: :completed? + validates :card_cvv, presence: true, if: :completed?, numericality: true, length: {is: 3} + validates :zip_code, presence: true, if: :completed?, format: { with: /\A\d{5}-\d{4}|\A\d{5}\z/ } + + attribute :status, :string, default: "pending" + + def completed? + self.status == "complete" + end + + def shipped + self.status == "shipped" + end + + def order_total + total = 0 + self.products.each do |product| + total += product.price + end + return total + + end + + def last_four + if self.status == "complete" || self.status == "shipped" + cc_last = self.card_number.to_s.slice(12..-1) + return cc_last + else + return "Order not Complete" + end + end + +end diff --git a/app/models/product.rb b/app/models/product.rb new file mode 100644 index 0000000000..1a27c88e07 --- /dev/null +++ b/app/models/product.rb @@ -0,0 +1,48 @@ +class Product < ApplicationRecord + validates :name, presence: true + validates :price, presence: true, numericality: { greater_than: 0 } + validates :quantity_avail, presence: true, numericality: { greater_than_or_equal_to: 0 } + + belongs_to :merchant + has_many :reviews + has_and_belongs_to_many :categories + has_and_belongs_to_many :orders + + has_attached_file :photo + validates_attachment_content_type :photo, content_type: /\Aimage\/.*\z/ + + def remove_one_from_stock + if self.quantity_avail > 0 + self.quantity_avail -= 1 + self.save + return true + else + return false + end + end + + def add_one_to_stock + self.quantity_avail += 1 + self.save + end + + def average_rating + rating = 0.0 + counter = 0 + if reviews.count == 0 + return "Not yet rated!" + end + reviews.each do |review| + if review[:rating] == nil + next + else + rating += review[:rating] + counter += 1 + end + end + + rating /= counter + return rating + end + +end diff --git a/app/models/review.rb b/app/models/review.rb new file mode 100644 index 0000000000..3f2d548ef5 --- /dev/null +++ b/app/models/review.rb @@ -0,0 +1,5 @@ +class Review < ApplicationRecord + belongs_to :product + validates :rating, presence: true, numericality: {only_integer: true, greater_than_or_equal_to: 1, less_than_or_equal_to: 5} + validates :product_id, presence: true +end diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb new file mode 100644 index 0000000000..698c401077 --- /dev/null +++ b/app/views/categories/index.html.erb @@ -0,0 +1,18 @@ +
+ + <% if @categories.count == 0 %> + Yikes! No categories meet those parameters. + <% else %> + Categories + <% end %> + + + <% @categories.each do |category| %> +
+
+ <%= link_to image_tag("http://www.dailypublic.com/sites/default/files/2015/Oct/buffalo-Niagara-Heritage-Village.jpg"), category_path(category.id), alt: "A category image placeholder" %> + <%= link_to category.name.upcase, category_path(category.id), alt: "Link to category products"%> +
+
+ <% end %> +
diff --git a/app/views/categories/new.html.erb b/app/views/categories/new.html.erb new file mode 100644 index 0000000000..623478ec82 --- /dev/null +++ b/app/views/categories/new.html.erb @@ -0,0 +1,6 @@ +<%= form_for @category do |f| %> + <%= f.label :name %> + <%= f.text_field :name %> + + <%= f.submit %> +<% end %> diff --git a/app/views/categories/show.html.erb b/app/views/categories/show.html.erb new file mode 100644 index 0000000000..0ec4529c8a --- /dev/null +++ b/app/views/categories/show.html.erb @@ -0,0 +1,20 @@ +
+ + <%= @category.name.upcase %> + <% if @category.products.count == 0 %> +
Yikes! No products are currently in this category. + <% end %> +
+ + <% @category.products.where(available: "Available").each do |product| %> +
+
+ + Product: <%= link_to product.name, product_path(product.id) %> + Average Rating: <%= product.average_rating %> + Price: <%= product.price %> + Quantity Available: <%= product.quantity_avail %> +
+
+ <% end %> +
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb new file mode 100644 index 0000000000..4e9c6dc2e6 --- /dev/null +++ b/app/views/layouts/application.html.erb @@ -0,0 +1,107 @@ + + + + + + + + + <%= content_for?(:title) ? yield(:title) : "Sourceress" %> + + <%= stylesheet_link_tag "application" %> + <%= javascript_include_tag "application", "data-turbolinks-track" => true %> + <%= csrf_meta_tags %> + + + + + + <%= yield :head %> + + + + <% if current_page?(root_path) %> + <% else %> + + <% end %> + + + <% if flash[:result_text] or flash[:messages] %> + + <% end %> + + <% if current_page?(root_path) %> + <% else %> +
+ +
+
+ +
+
+ +
+ <% 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/_form.html.erb b/app/views/merchants/_form.html.erb new file mode 100644 index 0000000000..9b81ffe949 --- /dev/null +++ b/app/views/merchants/_form.html.erb @@ -0,0 +1,8 @@ +

Partial Form

+<%= form_for @merchant do |f| %> + + <%= f.label :upload_merchant_photo %> + <%= f.file_field :photo %> + + <%= f.submit %> +<% end %> diff --git a/app/views/merchants/edit.html.erb b/app/views/merchants/edit.html.erb new file mode 100644 index 0000000000..d44c608b6a --- /dev/null +++ b/app/views/merchants/edit.html.erb @@ -0,0 +1 @@ +<%= render partial: "form" %> diff --git a/app/views/merchants/index.html.erb b/app/views/merchants/index.html.erb new file mode 100644 index 0000000000..cf0d97adf1 --- /dev/null +++ b/app/views/merchants/index.html.erb @@ -0,0 +1,18 @@ +
+ + <% if @merchants.count == 0 %> + Yikes! No merchants meet those parameters. + <% else %> + Merchant Gallery + <% end %> + + + <% @merchants.each do |merchant| %> +
+
+ <%= link_to image_tag("http://www.dailypublic.com/sites/default/files/2015/Oct/buffalo-Niagara-Heritage-Village.jpg"), merchant_path(merchant.id), alt: "A merchant's picture" %> + <%= link_to merchant.username.upcase, merchant_path(merchant.id), alt: "Link to merchant's products"%> +
+
+ <% end %> +
diff --git a/app/views/merchants/new.html.erb b/app/views/merchants/new.html.erb new file mode 100644 index 0000000000..583476d688 --- /dev/null +++ b/app/views/merchants/new.html.erb @@ -0,0 +1,2 @@ +

Merchants#new

+<%= render partial: "form" %> diff --git a/app/views/merchants/show.html.erb b/app/views/merchants/show.html.erb new file mode 100644 index 0000000000..1ef4bf09e3 --- /dev/null +++ b/app/views/merchants/show.html.erb @@ -0,0 +1,17 @@ +
+ + + Welcome to <%= @merchant.username.upcase %> +
+
+ + <% @merchant.products.where(available: "Available").each do |product| %> +
+
+ <%= link_to image_tag("http://www.dailypublic.com/sites/default/files/2015/Oct/buffalo-Niagara-Heritage-Village.jpg"), product_path(product.id), alt: "A product image placeholder" %> + <%= link_to product.name.upcase, product_path(product.id) %> + <%= product.price %> +
+
+ <% end %> +
diff --git a/app/views/orders/_form.html.erb b/app/views/orders/_form.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/views/orders/confirm.html.erb b/app/views/orders/confirm.html.erb new file mode 100644 index 0000000000..86ddecc297 --- /dev/null +++ b/app/views/orders/confirm.html.erb @@ -0,0 +1,23 @@ +
+ <% @order = Order.find_by(id: params[:id]) %> + Order # <%= @order.id %> Confirmed + <% product_array = @order.products.to_a %> + +
+ +
+ +
diff --git a/app/views/orders/create.html.erb b/app/views/orders/create.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/views/orders/destroy.html.erb b/app/views/orders/destroy.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/views/orders/edit.html.erb b/app/views/orders/edit.html.erb new file mode 100644 index 0000000000..fb3ad470bb --- /dev/null +++ b/app/views/orders/edit.html.erb @@ -0,0 +1,31 @@ +<%= form_for @order do |f| %> + + <%= f.label :name %> + <%= f.text_field :name %> + + <%= f.label :address, "Street Address" %> + <%= f.text_field :address %> + + <%= f.label :city %> + <%= f.text_field :city %> + + <%= f.label :state %> + <%= f.text_field :state %> + + <%= f.label :zip_code %> + <%= f.text_field :zip_code %> + + <%= f.label :email %> + <%= f.text_field :email %> + + <%= f.label :card_number %> + <%= f.text_field :card_number %> + + <%= f.label :card_exp, 'Expiration date' %> + <%= f.date_select :card_exp, :use_month_numbers => true, :discard_day => true, :start_year => Date.today.year, :end_year => (Date.today.year+10), :order => [:month, :year] %> + + <%= f.label :card_cvv %> + <%= f.text_field :card_cvv %> + + <%= f.submit "Complete Order"%> +<% end %> diff --git a/app/views/orders/index.html.erb b/app/views/orders/index.html.erb new file mode 100644 index 0000000000..2d124aea42 --- /dev/null +++ b/app/views/orders/index.html.erb @@ -0,0 +1,87 @@ +
+ +
+ + <% if @merch_orders == nil %> + No orders yet. + <% elsif params[:status] %> + Your <%= params[:status].capitalize %> Merchant Orders + <% else %> + All Merchant Orders + <% end %> + + <% @number_of_orders = @merch_orders.to_a.uniq {|o| o.id} %> +

TOTAL ORDERS: <%= @number_of_orders.length %>

+ + + <% @total_revenue = 0.00 %> + <% @merch_orders.to_a.each do |orders| %> + <% @total = 0.00 %> + +
+
    + + +
  • Order ID: <%= link_to orders.id, indi_order_path(orders.id.to_i) %>
  • +
  • <%= orders.status %>
  • +
  • <%= orders.created_at.strftime("%B %d, %Y") %>
  • +
  • <%= link_to orders.product_name, product_path(orders.product_id.to_i) %>
  • +
  • <%= orders.product_price.to_f %>
  • + <% @total += orders.product_price.to_f %> + <% @total_revenue += @total %> +
  • Order Total: <%= @total %>
  • +
+
+ <%= link_to ship_order_path(orders.id.to_i), method: :patch do %> + Mark Shipped + <% end %> + <%= link_to indi_order_path(orders.id.to_i), method: :get do %> + View Order + <% end %> +
+ +
+ <% end %> + +
+ <% if params[:status] %> + Total Revenue for <%= params[:status].capitalize %> Orders: <%= @total_revenue %> + <% else %> + Total Revenue for All Orders: <%= @total_revenue %> + <% end %> +
+ + + + + + +
+ +<%= link_to merchant_orders_path(params[:merchant_id].to_i, :status => "pending") do%> +Show Pending Orders +<% end %> + +<%= link_to merchant_orders_path(params[:merchant_id].to_i, :status => "complete") do%> +Show Complete Orders +<% end %> + +<%= link_to merchant_orders_path(params[:merchant_id].to_i, :status => "shipped") do%> +Show Shipped Orders +<% end %> + +<%= link_to merchant_orders_path(params[:merchant_id].to_i) do%> +Show All Orders +<% end %> +
+ +
+
diff --git a/app/views/orders/individual_order.html.erb b/app/views/orders/individual_order.html.erb new file mode 100644 index 0000000000..b33be2721d --- /dev/null +++ b/app/views/orders/individual_order.html.erb @@ -0,0 +1,23 @@ +
+ + + <% if @order.status == "pending" %> + No order info yet. + <% else @order.status == "complete" || @order.status == "shipped" %> + Order from <%= @order.name %> + <% end %> + + + +
+
    +
  • ID: <%= @order.id %>
  • +
  • Name: <%= @order.name %>
  • +
  • Email: <%= @order.email %>
  • +
  • Address: <%= @order.address %>
  • +
  • Zip Code: <%= @order.zip_code %>
  • +
  • Card Identifier: <%= @order.last_four %>
  • +
  • Card Expiration: <%= @order.card_exp %>
  • +
+
+
diff --git a/app/views/orders/new.html.erb b/app/views/orders/new.html.erb new file mode 100644 index 0000000000..8dcab705c4 --- /dev/null +++ b/app/views/orders/new.html.erb @@ -0,0 +1,24 @@ + diff --git a/app/views/orders/shipped.html.erb b/app/views/orders/shipped.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/views/orders/show.html.erb b/app/views/orders/show.html.erb new file mode 100644 index 0000000000..c3f6e39b2d --- /dev/null +++ b/app/views/orders/show.html.erb @@ -0,0 +1,35 @@ +
+ <% if @order.products.count == 0 %> +

There's nothing in your cart!

+ <% end %> + + <% product_array = @order.products.to_a %> + +
+
    + <% product_array.uniq.each do |product| %> +
  • + <%= link_to product.name.upcase, product_path(product.id) %> Quantity: <%= product_array.count(product) %> Subtotal: <%= product_array.count(product) * product.price %> + + + <%= link_to add_product_path(product), method: :patch do %> + +1 + <% end %> + <%= link_to remove_product_path(product), method: :patch do %> + -1 + <% end %> +
  • + <% end %> + +
  • Order Subtotal: <%= @order.order_total %>
  • +
+
+ + <%= link_to products_path do %> + Keep Shopping! + <% end %> + <%= link_to edit_order_path(@order.id) do %> + Checkout + <% end %> + +
diff --git a/app/views/orders/update.html.erb b/app/views/orders/update.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/views/products/edit.html.erb b/app/views/products/edit.html.erb new file mode 100644 index 0000000000..5dcfe2bc4c --- /dev/null +++ b/app/views/products/edit.html.erb @@ -0,0 +1,26 @@ +<%= form_for @product do |f| %> + <%= f.label :name %> + <%= f.text_field :name %> + + + <%= f.label :price %> + <%= f.text_field :price %> + + <%= f.label :quantity_avail %> + <%= f.text_field :quantity_avail %> + + <%= f.label :description %> + <%= f.text_field :description %> + + <%= f.label :product_category %> + <%= f.select :categories, options_for_select(Category.all.collect{ |c| c.name}), { :prompt => "SELECT UP TO 5"}, { :multiple => true, :size => 5 } %> + + + <%= f.label :upload_product_photo %> + <%= f.file_field :photo %> + + <%= f.label :status %> + <%= f.select(:available, ["Available", "Retired"])%> + + <%= f.submit %> +<% end %> diff --git a/app/views/products/home.html.erb b/app/views/products/home.html.erb new file mode 100644 index 0000000000..f7c7e4efe6 --- /dev/null +++ b/app/views/products/home.html.erb @@ -0,0 +1,75 @@ +
+ + Featured Product + +
+
+ +
    +
  • <%= link_to image_tag("http://mediad.publicbroadcasting.net/p/wvpn/files/styles/x_large/public/201704/IMG_0688.jpg"), product_path(12) %>
  • +
  • <%= link_to image_tag("http://i.telegraph.co.uk/multimedia/archive/02834/smog-skyscrapers_2834586k.jpg"), product_path(9), alt: "Spooky smog and skyscrapers." %>
  • +
  • <%= link_to image_tag("https://www.epicurus.com/beverages/wp-content/uploads/2012/10/smokking-cauldron.jpg"), product_path(4), alt: "Poison punch"%>
  • +
  • <%= link_to image_tag("https://cosmos-magazine.imgix.net/file/spina/photo/10994/170407_Frogs_Full.jpg?fit=clip&w=835"), product_path(6), alt: "Toads" %>
  • +
+
+ +
+ +
+
+ + + + + +
diff --git a/app/views/products/index.html.erb b/app/views/products/index.html.erb new file mode 100644 index 0000000000..72b7b6004a --- /dev/null +++ b/app/views/products/index.html.erb @@ -0,0 +1,26 @@ +
+ + <% if @products.count == 0 %> + Yikes! No products meet those parameters. + <% else %> + Product Gallery + <% end %> + + + <% @products.each do |product| %> +
+
+ <% if product.photo.file? %> + <%= link_to image_tag(product.photo.url), product_path(product.id) %> + <% else %> + <%= link_to image_tag("http://www.visitbuffaloniagara.com/content/uploads/sv-event-images/434cfb09-bb34-449b-ac6c-d400b6a53f1d.jpg"), product_path(product.id), alt: "A product image placeholder" %> + <% end %> + <%= link_to product.name.upcase, product_path(product.id) %> + <%= product.price %> + <% if product.merchant.id == session[:user_id] %> + <%= link_to "Edit this Product", edit_product_path(product.id)%> + <% end %> +
+
+ <% end %> +
diff --git a/app/views/products/new.html.erb b/app/views/products/new.html.erb new file mode 100644 index 0000000000..65c4daf311 --- /dev/null +++ b/app/views/products/new.html.erb @@ -0,0 +1,22 @@ +<%= form_for @product, url: products_path, :html => { :multipart => true } do |f| %> + <%= f.label :name %> + <%= f.text_field :name %> + + <%= f.label :price %> + <%= f.text_field :price %> + + <%= f.label :quantity_available %> + <%= f.text_field :quantity_avail %> + + <%= f.label :description %> + <%= f.text_field :description %> + + <%= f.label :product_category %> + <%= f.select :categories, options_for_select(Category.all.collect{ |c| c.name}), { :prompt => "SELECT UP TO 5 CATEGORIES"}, { :multiple => true, :size => 5 } %> + + + <%= f.label :upload_product_photo %> + <%= f.file_field :photo %> + + <%= f.submit %> +<% end %> diff --git a/app/views/products/root.html.erb b/app/views/products/root.html.erb new file mode 100644 index 0000000000..960993119f --- /dev/null +++ b/app/views/products/root.html.erb @@ -0,0 +1,113 @@ +<% if current_page?(root_path) %> + + <% else %> + + <% end %> + + <%= link_to "Sourceress", home_path %> + +
+ +
+ + + + + + + diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb new file mode 100644 index 0000000000..8ffa479e8f --- /dev/null +++ b/app/views/products/show.html.erb @@ -0,0 +1,75 @@ +
+ +
+ +
+
+ <% if @product.photo.file? %> + <%= image_tag @product.photo.url %> + <% else %> + + <% end %> +
+ +
+

<%= @product.name.upcase %> by

+

+ <%= link_to @product.merchant.username, merchant_path(@product.merchant.id) %>

+ <% if @product.description != nil %> +

Description: <%= @product.description %>

+ <% end %> +

$<%= @product.price %>

+

Average Rating: <%= @product.average_rating %>

+ <% if @product.categories.count > 0 %> +

Categories: <% @product.categories.each do |category| %> + <%= link_to category.name, category_path(category.id) %> + <% end %> + <% end %>

+ <% if @product.quantity_avail > 0 %> +

In Stock

+ <% if @product.quantity_avail <= 5 %> +

Only <%= @product.quantity_avail%> left!

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

Out of Stock

+ <% end %> + <% if @product.quantity_avail == 0 %> + + <%= link_to "Not available: Keep Shopping!", products_path, method: :get %> + <% elsif session[:order_id] == nil && @product.quantity_avail > 0 %> + <%= link_to add_product_path(@product), method: :patch do %> + Add to Cart + <% end %> + <% elsif @product.quantity_avail > 0 %> + <%= link_to add_product_path(@product), method: :patch do%> + Add to Cart + <% end %> + <% end %> + + <%= link_to new_product_review_path(@product.id) do %> + Leave a Review + <% end %> +
+
+ + + + +
+
+
Reviews
+ <% if @product.reviews.count == 0 %> +
This Product has not Been Reviewed
+ <% else %> + <% @product.reviews.each do |review| %> +
+ +

Rating: <%= review.rating %>

+

<%= review.text_review %>

+
+
+ <% end %> + <% end %> +
+
+ diff --git a/app/views/reviews/_form.html.erb b/app/views/reviews/_form.html.erb new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/app/views/reviews/_form.html.erb @@ -0,0 +1 @@ + diff --git a/app/views/reviews/create.html.erb b/app/views/reviews/create.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/views/reviews/destroy.html.erb b/app/views/reviews/destroy.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/views/reviews/edit.html.erb b/app/views/reviews/edit.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/views/reviews/index.html.erb b/app/views/reviews/index.html.erb new file mode 100644 index 0000000000..7541081eb9 --- /dev/null +++ b/app/views/reviews/index.html.erb @@ -0,0 +1 @@ +

<%= @reviews %>

diff --git a/app/views/reviews/new.html.erb b/app/views/reviews/new.html.erb new file mode 100644 index 0000000000..8dd5108d94 --- /dev/null +++ b/app/views/reviews/new.html.erb @@ -0,0 +1,19 @@ + +
+ <% @product = Product.find_by(id: params[:product_id]) %> + + + <%= form_for @review, url: product_reviews_path, method: :post do |f| %> + + + + <%= f.label :rating %> + <%= f.select :rating, [1,2,3,4,5], required: true %> + + <%= f.label :text_review %> + <%= f.text_area :text_review, required: true %> + + <%= f.submit %> + <% end %> + +
diff --git a/app/views/reviews/show.html.erb b/app/views/reviews/show.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/views/reviews/update.html.erb b/app/views/reviews/update.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bin/bundle b/bin/bundle new file mode 100755 index 0000000000..66e9889e8b --- /dev/null +++ b/bin/bundle @@ -0,0 +1,3 @@ +#!/usr/bin/env ruby +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +load Gem.bin_path('bundler', 'bundle') diff --git a/bin/rails b/bin/rails new file mode 100755 index 0000000000..5badb2fde0 --- /dev/null +++ b/bin/rails @@ -0,0 +1,9 @@ +#!/usr/bin/env ruby +begin + load File.expand_path('../spring', __FILE__) +rescue LoadError => e + raise unless e.message.include?('spring') +end +APP_PATH = File.expand_path('../config/application', __dir__) +require_relative '../config/boot' +require 'rails/commands' diff --git a/bin/rake b/bin/rake new file mode 100755 index 0000000000..d87d5f5781 --- /dev/null +++ b/bin/rake @@ -0,0 +1,9 @@ +#!/usr/bin/env ruby +begin + load File.expand_path('../spring', __FILE__) +rescue LoadError => e + raise unless e.message.include?('spring') +end +require_relative '../config/boot' +require 'rake' +Rake.application.run diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000000..78c4e861dc --- /dev/null +++ b/bin/setup @@ -0,0 +1,38 @@ +#!/usr/bin/env ruby +require 'pathname' +require 'fileutils' +include FileUtils + +# path to your application root. +APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +chdir APP_ROOT do + # This script is a starting point to setup your application. + # Add necessary setup steps to this file. + + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') + + # Install JavaScript dependencies if using Yarn + # system('bin/yarn') + + + # puts "\n== Copying sample files ==" + # unless File.exist?('config/database.yml') + # cp 'config/database.yml.sample', 'config/database.yml' + # end + + puts "\n== Preparing database ==" + system! 'bin/rails db:setup' + + puts "\n== Removing old logs and tempfiles ==" + system! 'bin/rails log:clear tmp:clear' + + puts "\n== Restarting application server ==" + system! 'bin/rails restart' +end diff --git a/bin/spring b/bin/spring new file mode 100755 index 0000000000..fb2ec2ebb4 --- /dev/null +++ b/bin/spring @@ -0,0 +1,17 @@ +#!/usr/bin/env ruby + +# This file loads spring without using Bundler, in order to be fast. +# It gets overwritten when you run the `spring binstub` command. + +unless defined?(Spring) + require 'rubygems' + require 'bundler' + + lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read) + spring = lockfile.specs.detect { |spec| spec.name == "spring" } + if spring + Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path + gem 'spring', spring.version + require 'spring/binstub' + end +end diff --git a/bin/update b/bin/update new file mode 100755 index 0000000000..a8e4462f20 --- /dev/null +++ b/bin/update @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +require 'pathname' +require 'fileutils' +include FileUtils + +# path to your application root. +APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +chdir APP_ROOT do + # This script is a way to update your development environment automatically. + # Add necessary update steps to this file. + + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') + + puts "\n== Updating database ==" + system! 'bin/rails db:migrate' + + puts "\n== Removing old logs and tempfiles ==" + system! 'bin/rails log:clear tmp:clear' + + puts "\n== Restarting application server ==" + system! 'bin/rails restart' +end diff --git a/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..a47233460d --- /dev/null +++ b/config/application.rb @@ -0,0 +1,25 @@ +require_relative 'boot' + +require 'rails/all' + +# Require the gems listed in Gemfile, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(*Rails.groups) + +module Betsy + class Application < Rails::Application + config.generators do |g| + # Force new test files to be generated in the minitest-spec style + g.test_framework :minitest, spec: true + + # Always use .js files, never .coffee + g.javascript_engine :js + end + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 5.1 + + # Settings in config/environments/* take precedence over those specified here. + # Application configuration should go into files in config/initializers + # -- all .rb files in that directory are automatically loaded. + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000000..30f5120df6 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,3 @@ +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) + +require 'bundler/setup' # Set up gems listed in the Gemfile. diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000000..3cba994bb2 --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: async + +production: + adapter: redis + url: redis://localhost:6379/1 + channel_prefix: betsy_production diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000000..6903bb6083 --- /dev/null +++ b/config/database.yml @@ -0,0 +1,85 @@ +# PostgreSQL. Versions 9.1 and up are supported. +# +# Install the pg driver: +# gem install pg +# On OS X with Homebrew: +# gem install pg -- --with-pg-config=/usr/local/bin/pg_config +# On OS X with MacPorts: +# gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config +# On Windows: +# gem install pg +# Choose the win32 build. +# Install PostgreSQL and put its /bin directory on your path. +# +# Configure Using Gemfile +# gem 'pg' +# +default: &default + adapter: postgresql + encoding: unicode + # For details on connection pooling, see Rails configuration guide + # http://guides.rubyonrails.org/configuring.html#database-pooling + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + +development: + <<: *default + database: betsy_development + + # The specified database role being used to connect to postgres. + # To create additional roles in postgres see `$ createuser --help`. + # When left blank, postgres will use the default role. This is + # the same name as the operating system user that initialized the database. + #username: betsy + + # The password associated with the postgres role (username). + #password: + + # Connect on a TCP socket. Omitted by default since the client uses a + # domain socket that doesn't need configuration. Windows does not have + # domain sockets, so uncomment these lines. + #host: localhost + + # The TCP port the server listens on. Defaults to 5432. + # If your server runs on a different port number, change accordingly. + #port: 5432 + + # Schema search path. The server defaults to $user,public + #schema_search_path: myapp,sharedapp,public + + # Minimum log levels, in increasing order: + # debug5, debug4, debug3, debug2, debug1, + # log, notice, warning, error, fatal, and panic + # Defaults to warning. + #min_messages: notice + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + <<: *default + database: betsy_test + +# As with config/secrets.yml, you never want to store sensitive information, +# like your database password, in your source code. If your source code is +# ever seen by anyone, they now have access to your database. +# +# Instead, provide the password as a unix environment variable when you boot +# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# for a full rundown on how to provide these environment variables in a +# production deployment. +# +# On Heroku and other platform providers, you may have a full connection URL +# available as an environment variable. For example: +# +# DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase" +# +# You can use this database configuration with: +# +# production: +# url: <%= ENV['DATABASE_URL'] %> +# +production: + <<: *default + database: betsy_production + username: betsy + password: <%= ENV['BETSY_DATABASE_PASSWORD'] %> diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000000..426333bb46 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,5 @@ +# Load the Rails application. +require_relative 'application' + +# Initialize the Rails application. +Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000000..ef73d3ad00 --- /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. + Paperclip.options[:command_path] = "/usr/local/bin/" + # In the development environment your application's code is reloaded on + # every request. This slows down response time but is perfect for development + # since you don't have to restart the web server when you make code changes. + config.cache_classes = false + + # Do not eager load code on boot. + config.eager_load = false + + # Show full error reports. + config.consider_all_requests_local = true + + # Enable/disable caching. By default caching is disabled. + if Rails.root.join('tmp/caching-dev.txt').exist? + config.action_controller.perform_caching = true + + config.cache_store = :memory_store + config.public_file_server.headers = { + 'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + + # Don't care if the mailer can't send. + config.action_mailer.raise_delivery_errors = false + + config.action_mailer.perform_caching = false + + # Print deprecation notices to the Rails logger. + config.active_support.deprecation = :log + + # Raise an error on page load if there are pending migrations. + config.active_record.migration_error = :page_load + + # Debug mode disables concatenation and preprocessing of assets. + # This option may cause significant delays in view rendering with a large + # number of complex assets. + config.assets.debug = true + + # Suppress logger output for asset requests. + config.assets.quiet = true + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true + + # Use an evented file watcher to asynchronously detect changes in source code, + # routes, locales, etc. This feature depends on the listen gem. + config.file_watcher = ActiveSupport::EventedFileUpdateChecker +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000000..9284f84839 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,91 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Attempt to read encrypted secrets from `config/secrets.yml.enc`. + # Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or + # `config/secrets.yml.key`. + config.read_encrypted_secrets = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? + + # Compress JavaScripts and CSS. + config.assets.js_compressor = :uglifier + # config.assets.css_compressor = :sass + + # Do not fallback to assets pipeline if a precompiled asset is missed. + config.assets.compile = false + + # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.action_controller.asset_host = 'http://assets.example.com' + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX + + # Mount Action Cable outside main process or domain + # config.action_cable.mount_path = nil + # config.action_cable.url = 'wss://example.com/cable' + # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + # config.force_ssl = true + + # Use the lowest log level to ensure availability of diagnostic information + # when problems arise. + config.log_level = :debug + + # Prepend all log lines with the following tags. + config.log_tags = [ :request_id ] + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Use a real queuing backend for Active Job (and separate queues per environment) + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "betsy_#{Rails.env}" + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true + + # Send deprecation notices to registered listeners. + config.active_support.deprecation = :notify + + # Use default logging formatter so that PID and timestamp are not suppressed. + config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require 'syslog/logger' + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000000..8e5cbde533 --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,42 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb. + + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! + config.cache_classes = true + + # Do not eager load code on boot. This avoids loading your whole application + # just for the purpose of running a single test. If you are using a tool that + # preloads Rails for running tests, you may have to set it to true. + config.eager_load = false + + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + 'Cache-Control' => "public, max-age=#{1.hour.seconds.to_i}" + } + + # Show full error reports and disable caching. + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Raise exceptions instead of rendering exception templates. + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment. + config.action_controller.allow_forgery_protection = false + config.action_mailer.perform_caching = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Print deprecation notices to the stderr. + config.active_support.deprecation = :stderr + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true +end diff --git a/config/initializers/application_controller_renderer.rb b/config/initializers/application_controller_renderer.rb new file mode 100644 index 0000000000..89d2efab2b --- /dev/null +++ b/config/initializers/application_controller_renderer.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# ActiveSupport::Reloader.to_prepare do +# ApplicationController.renderer.defaults.merge!( +# http_host: 'example.org', +# https: false +# ) +# end diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb new file mode 100644 index 0000000000..f7617edb52 --- /dev/null +++ b/config/initializers/assets.rb @@ -0,0 +1,16 @@ +# Be sure to restart your server when you modify this file. + +# Version of your assets, change this if you want to expire all your assets. +Rails.application.config.assets.version = '1.0' + +# Add additional assets to the asset load path. +# Rails.application.config.assets.paths << Emoji.images_path +# Add Yarn node_modules folder to the asset load path. +Rails.application.config.assets.paths << Rails.root.join('node_modules') + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in the app/assets +# folder are already added. +# Rails.application.config.assets.precompile += %w( admin.js admin.css ) + +Rails.application.config.assets.precompile += %w( home.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/omniauth.rb b/config/initializers/omniauth.rb new file mode 100644 index 0000000000..fd4416122a --- /dev/null +++ b/config/initializers/omniauth.rb @@ -0,0 +1,3 @@ +Rails.application.config.middleware.use OmniAuth::Builder do + provider :github, ENV["GITHUB_CLIENT_ID"], ENV["GITHUB_CLIENT_SECRET"], scope: "user:email" +end diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb new file mode 100644 index 0000000000..bbfc3961bf --- /dev/null +++ b/config/initializers/wrap_parameters.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. + +# This file contains settings for ActionController::ParamsWrapper which +# is enabled by default. + +# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. +ActiveSupport.on_load(:action_controller) do + wrap_parameters format: [:json] +end + +# To enable root element in JSON for ActiveRecord objects. +# ActiveSupport.on_load(:active_record) do +# self.include_root_in_json = true +# end diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000000..decc5a8573 --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,33 @@ +# Files in the config/locales directory are used for internationalization +# and are automatically loaded by Rails. If you want to use locales other +# than English, add the necessary files in this directory. +# +# To use the locales, use `I18n.t`: +# +# I18n.t 'hello' +# +# In views, this is aliased to just `t`: +# +# <%= t('hello') %> +# +# To use a different locale, set it with `I18n.locale`: +# +# I18n.locale = :es +# +# This would use the information in config/locales/es.yml. +# +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# 'true': 'foo' +# +# To learn more, please read the Rails Internationalization guide +# available at http://guides.rubyonrails.org/i18n.html. + +en: + hello: "Hello world" diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000000..1e19380dcb --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,56 @@ +# Puma can serve each request in a thread from an internal thread pool. +# The `threads` method setting takes two numbers: a minimum and maximum. +# Any libraries that use thread pools should be configured to match +# the maximum value specified for Puma. Default is set to 5 threads for minimum +# and maximum; this matches the default thread size of Active Record. +# +threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +threads threads_count, threads_count + +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +# +port ENV.fetch("PORT") { 3000 } + +# Specifies the `environment` that Puma will run in. +# +environment ENV.fetch("RAILS_ENV") { "development" } + +# Specifies the number of `workers` to boot in clustered mode. +# Workers are forked webserver processes. If using threads and workers together +# the concurrency of the application would be max `threads` * `workers`. +# Workers do not work on JRuby or Windows (both of which do not support +# processes). +# +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } + +# Use the `preload_app!` method when specifying a `workers` number. +# This directive tells Puma to first boot the application and load code +# before forking the application. This takes advantage of Copy On Write +# process behavior so workers use less memory. If you use this option +# you need to make sure to reconnect any threads in the `on_worker_boot` +# block. +# +# preload_app! + +# If you are preloading your application and using Active Record, it's +# recommended that you close any connections to the database before workers +# are forked to prevent connection leakage. +# +# before_fork do +# ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord) +# end + +# The code in the `on_worker_boot` will be called if you are using +# clustered mode by specifying a number of `workers`. After each worker +# process is booted, this block will be run. If you are using the `preload_app!` +# option, you will want to use this block to reconnect to any threads +# or connections that may have been created at application boot, as Ruby +# cannot share connections between processes. +# +# on_worker_boot do +# ActiveRecord::Base.establish_connection if defined?(ActiveRecord) +# end +# + +# Allow puma to be restarted by `rails restart` command. +plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000000..ffdd553116 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,51 @@ +Rails.application.routes.draw do + # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html + + root to: 'products#root', as: "root" + get '/home', to: 'products#home', as: "home" + + + + patch 'orders/:id/shipped', to: 'orders#shipped', as: 'ship_order' + + get 'orders/:id/individual_order', to: 'orders#individual_order', as: 'indi_order' + + resources :products do + resources :reviews, only: [:new, :create] + + end + + resources :merchants do + get '/products', to: 'products#index' + resources :orders, only: [:index] + end + + resources :categories, except: [:update, :edit] do + resources :products, only: [:index] + end + + resources :orders, except: [:destroy] do + get '/orders/:id/confirm', to: 'orders#confirm', as: 'confirm_order' + end + + get "/auth/:provider/callback", to: "sessions#create", as: 'auth_callback' + + post '/logout', to: 'sessions#logout', as: 'logout' + + patch 'products/:id/add_product_to_cart', to: 'products#add_product_to_cart', as: 'add_product' + + patch 'products/:id/remove_product_from_cart', to: 'products#remove_product_from_cart', as: 'remove_product' + + + + + + # resources :merchants do + # get '/products', to: 'products#index' + # end + # + # resources :categories, except: [:edit] do + # get '/products', to: 'products#index' + # end + +end diff --git a/config/secrets.yml b/config/secrets.yml new file mode 100644 index 0000000000..6c85239306 --- /dev/null +++ b/config/secrets.yml @@ -0,0 +1,32 @@ +# Be sure to restart your server when you modify this file. + +# Your secret key is used for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! + +# Make sure the secret is at least 30 characters and all random, +# no regular words or you'll be exposed to dictionary attacks. +# You can use `rails secret` to generate a secure secret key. + +# Make sure the secrets in this file are kept private +# if you're sharing your code publicly. + +# Shared secrets are available across all environments. + +# shared: +# api_key: a1B2c3D4e5F6 + +# Environmental secrets are only available for that specific environment. + +development: + secret_key_base: 68bb246ed097645198656753e163fd6fa9feb15482ca49c0b9cc250013ee665548ff66dce1ffc81b4c1fcd9c48986ca3444edd67c83ed9e7f1145c53c7dd2b3d + +test: + secret_key_base: e352ccc32555d0d7451a109601441e05ac433439736ea360cdad6086e351720a3e2ceef986e243c0042d93d09e659734878154a4524e64557bc5c61b0d8dd478 + +# Do not keep production secrets in the unencrypted secrets file. +# Instead, either read values from the environment. +# Or, use `bin/rails secrets:setup` to configure encrypted secrets +# and move the `production:` environment over there. + +production: + secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> diff --git a/config/spring.rb b/config/spring.rb new file mode 100644 index 0000000000..c9119b40c0 --- /dev/null +++ b/config/spring.rb @@ -0,0 +1,6 @@ +%w( + .ruby-version + .rbenv-vars + tmp/restart.txt + tmp/caching-dev.txt +).each { |path| Spring.watch(path) } diff --git a/db/migrate/20171017205403_create_merchants.rb b/db/migrate/20171017205403_create_merchants.rb new file mode 100644 index 0000000000..824068f3d8 --- /dev/null +++ b/db/migrate/20171017205403_create_merchants.rb @@ -0,0 +1,9 @@ +class CreateMerchants < ActiveRecord::Migration[5.1] + def change + create_table :merchants do |t| + t.string :username, null: false + t.string :email, null: false + t.timestamps + end + end +end diff --git a/db/migrate/20171017205415_create_products.rb b/db/migrate/20171017205415_create_products.rb new file mode 100644 index 0000000000..02472100c8 --- /dev/null +++ b/db/migrate/20171017205415_create_products.rb @@ -0,0 +1,11 @@ +class CreateProducts < ActiveRecord::Migration[5.1] + def change + create_table :products do |t| + t.string :name + t.decimal :price + t.integer :quantity_avail + t.belongs_to :merchant, index: true + t.timestamps + end + end +end diff --git a/db/migrate/20171017205439_create_orders.rb b/db/migrate/20171017205439_create_orders.rb new file mode 100644 index 0000000000..fd39d8fe12 --- /dev/null +++ b/db/migrate/20171017205439_create_orders.rb @@ -0,0 +1,15 @@ +class CreateOrders < ActiveRecord::Migration[5.1] + def change + create_table :orders do |t| + t.string :status + t.string :email + t.string :address + t.string :name + t.string :card_number + t.string :card_exp + t.string :card_cvv + t.string :zip_code + t.timestamps + end + end +end diff --git a/db/migrate/20171017205452_create_categories.rb b/db/migrate/20171017205452_create_categories.rb new file mode 100644 index 0000000000..c7c46b747a --- /dev/null +++ b/db/migrate/20171017205452_create_categories.rb @@ -0,0 +1,8 @@ +class CreateCategories < ActiveRecord::Migration[5.1] + def change + create_table :categories do |t| + t.string :name + t.timestamps + end + end +end diff --git a/db/migrate/20171017205519_create_reviews.rb b/db/migrate/20171017205519_create_reviews.rb new file mode 100644 index 0000000000..cfdf936c8f --- /dev/null +++ b/db/migrate/20171017205519_create_reviews.rb @@ -0,0 +1,10 @@ +class CreateReviews < ActiveRecord::Migration[5.1] + def change + create_table :reviews do |t| + t.integer :rating + t.string :text_review + t.belongs_to :product, index: true + t.timestamps + end + end +end diff --git a/db/migrate/20171017211418_create_products_categories_join.rb b/db/migrate/20171017211418_create_products_categories_join.rb new file mode 100644 index 0000000000..3af322f986 --- /dev/null +++ b/db/migrate/20171017211418_create_products_categories_join.rb @@ -0,0 +1,8 @@ +class CreateProductsCategoriesJoin < ActiveRecord::Migration[5.1] + def change + create_table :products_categories do |t| + t.belongs_to :product, index: true + t.belongs_to :category, index: true + end + end +end diff --git a/db/migrate/20171017211619_create_orders_products_join.rb b/db/migrate/20171017211619_create_orders_products_join.rb new file mode 100644 index 0000000000..ff97b17c90 --- /dev/null +++ b/db/migrate/20171017211619_create_orders_products_join.rb @@ -0,0 +1,8 @@ +class CreateOrdersProductsJoin < ActiveRecord::Migration[5.1] + def change + create_table :orders_products do |t| + t.belongs_to :product, index: true + t.belongs_to :order, index: true + end + end +end diff --git a/db/migrate/20171018182552_remove_merchant_id_column.rb b/db/migrate/20171018182552_remove_merchant_id_column.rb new file mode 100644 index 0000000000..fabe132e08 --- /dev/null +++ b/db/migrate/20171018182552_remove_merchant_id_column.rb @@ -0,0 +1,5 @@ +class RemoveMerchantIdColumn < ActiveRecord::Migration[5.1] + def change + remove_column :products, :merchant_id + end +end diff --git a/db/migrate/20171018195147_add_merchant_column.rb b/db/migrate/20171018195147_add_merchant_column.rb new file mode 100644 index 0000000000..6a7f567358 --- /dev/null +++ b/db/migrate/20171018195147_add_merchant_column.rb @@ -0,0 +1,5 @@ +class AddMerchantColumn < ActiveRecord::Migration[5.1] + def change + add_reference :products, :merchant, foreign_key: true + end +end diff --git a/db/migrate/20171019164759_rename_products_categories_table.rb b/db/migrate/20171019164759_rename_products_categories_table.rb new file mode 100644 index 0000000000..ee3e2247c6 --- /dev/null +++ b/db/migrate/20171019164759_rename_products_categories_table.rb @@ -0,0 +1,5 @@ +class RenameProductsCategoriesTable < ActiveRecord::Migration[5.1] + def change + rename_table :products_categories, :categories_products + end +end diff --git a/db/migrate/20171022040645_change_expiration_data_type.rb b/db/migrate/20171022040645_change_expiration_data_type.rb new file mode 100644 index 0000000000..fd0953b130 --- /dev/null +++ b/db/migrate/20171022040645_change_expiration_data_type.rb @@ -0,0 +1,6 @@ +class ChangeExpirationDataType < ActiveRecord::Migration[5.1] + def change + remove_column :orders, :card_exp + add_column :orders, :card_exp, :date + end +end diff --git a/db/migrate/20171022054516_add_attachment_photo_to_products.rb b/db/migrate/20171022054516_add_attachment_photo_to_products.rb new file mode 100644 index 0000000000..bee171c473 --- /dev/null +++ b/db/migrate/20171022054516_add_attachment_photo_to_products.rb @@ -0,0 +1,11 @@ +class AddAttachmentPhotoToProducts < ActiveRecord::Migration[5.1] + def self.up + change_table :products do |t| + t.attachment :photo + end + end + + def self.down + remove_attachment :products, :photo + end +end diff --git a/db/migrate/20171022060446_add_attachment_photo_to_merchants.rb b/db/migrate/20171022060446_add_attachment_photo_to_merchants.rb new file mode 100644 index 0000000000..43466afb1a --- /dev/null +++ b/db/migrate/20171022060446_add_attachment_photo_to_merchants.rb @@ -0,0 +1,11 @@ +class AddAttachmentPhotoToMerchants < ActiveRecord::Migration[5.1] + def self.up + change_table :merchants do |t| + t.attachment :photo + end + end + + def self.down + remove_attachment :merchants, :photo + end +end diff --git a/db/migrate/20171022183004_add_city_state_columns.rb b/db/migrate/20171022183004_add_city_state_columns.rb new file mode 100644 index 0000000000..a1c04295c5 --- /dev/null +++ b/db/migrate/20171022183004_add_city_state_columns.rb @@ -0,0 +1,6 @@ +class AddCityStateColumns < ActiveRecord::Migration[5.1] + def change + add_column :orders, :city, :string + add_column :orders, :state, :string + end +end diff --git a/db/migrate/20171023195353_add_uid_and_provider_to_merchant.rb b/db/migrate/20171023195353_add_uid_and_provider_to_merchant.rb new file mode 100644 index 0000000000..f52444b05e --- /dev/null +++ b/db/migrate/20171023195353_add_uid_and_provider_to_merchant.rb @@ -0,0 +1,6 @@ +class AddUidAndProviderToMerchant < ActiveRecord::Migration[5.1] + def change + add_column :merchants, :uid, :integer + add_column :merchants, :provider, :string + end +end diff --git a/db/migrate/20171023220504_add_status_to_product.rb b/db/migrate/20171023220504_add_status_to_product.rb new file mode 100644 index 0000000000..4f390a599a --- /dev/null +++ b/db/migrate/20171023220504_add_status_to_product.rb @@ -0,0 +1,5 @@ +class AddStatusToProduct < ActiveRecord::Migration[5.1] + def change + add_column :products, :available, :boolean, :default => true + end +end diff --git a/db/migrate/20171023223701_change_status_to_string_for_products.rb b/db/migrate/20171023223701_change_status_to_string_for_products.rb new file mode 100644 index 0000000000..3ac85a675f --- /dev/null +++ b/db/migrate/20171023223701_change_status_to_string_for_products.rb @@ -0,0 +1,5 @@ +class ChangeStatusToStringForProducts < ActiveRecord::Migration[5.1] + def change + change_column :products, :available, :string, :default => "Available" + end +end diff --git a/db/migrate/20171023231206_add_default_status_for_products.rb b/db/migrate/20171023231206_add_default_status_for_products.rb new file mode 100644 index 0000000000..99ae987ee8 --- /dev/null +++ b/db/migrate/20171023231206_add_default_status_for_products.rb @@ -0,0 +1,5 @@ +class AddDefaultStatusForProducts < ActiveRecord::Migration[5.1] + def up + Product.where(available: nil).update_all(available: "Available") + end +end diff --git a/db/migrate/20171024225856_add_product_description_column.rb b/db/migrate/20171024225856_add_product_description_column.rb new file mode 100644 index 0000000000..4cb518374d --- /dev/null +++ b/db/migrate/20171024225856_add_product_description_column.rb @@ -0,0 +1,5 @@ +class AddProductDescriptionColumn < ActiveRecord::Migration[5.1] + def change + add_column :products, :description, :string + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000000..acd058f371 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,92 @@ +# 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: 20171024225856) do + + # These are extensions that must be enabled in order to support this database + enable_extension "plpgsql" + + create_table "categories", force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "categories_products", force: :cascade do |t| + t.bigint "product_id" + t.bigint "category_id" + t.index ["category_id"], name: "index_categories_products_on_category_id" + t.index ["product_id"], name: "index_categories_products_on_product_id" + end + + create_table "merchants", force: :cascade do |t| + t.string "username", null: false + t.string "email", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "photo_file_name" + t.string "photo_content_type" + t.integer "photo_file_size" + t.datetime "photo_updated_at" + t.integer "uid" + t.string "provider" + end + + create_table "orders", force: :cascade do |t| + t.string "status" + t.string "email" + t.string "address" + t.string "name" + t.string "card_number" + t.string "card_cvv" + t.string "zip_code" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.date "card_exp" + t.string "city" + t.string "state" + end + + create_table "orders_products", force: :cascade do |t| + t.bigint "product_id" + t.bigint "order_id" + t.index ["order_id"], name: "index_orders_products_on_order_id" + t.index ["product_id"], name: "index_orders_products_on_product_id" + end + + create_table "products", force: :cascade do |t| + t.string "name" + t.decimal "price" + t.integer "quantity_avail" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.bigint "merchant_id" + t.string "photo_file_name" + t.string "photo_content_type" + t.integer "photo_file_size" + t.datetime "photo_updated_at" + t.string "available", default: "Available" + t.string "description" + t.index ["merchant_id"], name: "index_products_on_merchant_id" + end + + create_table "reviews", force: :cascade do |t| + t.integer "rating" + t.string "text_review" + t.bigint "product_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["product_id"], name: "index_reviews_on_product_id" + end + + add_foreign_key "products", "merchants" +end diff --git a/db/seed_data/categories.csv b/db/seed_data/categories.csv new file mode 100644 index 0000000000..12b00d013e --- /dev/null +++ b/db/seed_data/categories.csv @@ -0,0 +1,8 @@ +name +brooms +cauldrons +miscellaneous +clothing +home remedies +household +outdoors diff --git a/db/seed_data/merchants.csv b/db/seed_data/merchants.csv new file mode 100644 index 0000000000..681391bb76 --- /dev/null +++ b/db/seed_data/merchants.csv @@ -0,0 +1,11 @@ +username,email +Wiccan Loans,moneynow@ghoulmail.com +Broom With A View,broomtastick@ghoulmail.com +Crone Jewels,jewellyc@zombiepost.com +Potion Our Wares,wareyouout@ghoulmail.com +Quality Curses,carryusaround@zombiepost.com +The Dark Markdown,whoknows@ghoulmail.com +Toadally Original,toadtastic@zombiepost.com +Browse a Spell,browsing@ghoulmail.com +Spell It Out,spellitout@zombiepost.com +Brews and Ghouls,bandg@zombiepost.com diff --git a/db/seed_data/products.csv b/db/seed_data/products.csv new file mode 100644 index 0000000000..86fd2e8f62 --- /dev/null +++ b/db/seed_data/products.csv @@ -0,0 +1,11 @@ +merchant_id,name,price,quantity_avail +1,toad stools,9.99,3 +2,witches brew,2.99,10 +3,wart cream,5.99,2 +4,gold cauldron,2.99,5 +5,Incredible Curses,17.99,12 +6,Frog Legs for All,18.99,3 +7,silk robe,35.99,6 +8,disappearing flask,10.99,4 +9,spooky smog,23.99,8 +10,Evil Spells to Cast,16.99,5 diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000000..af3465ed2a --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,70 @@ +require 'csv' + +MERCHANT_FILE = Rails.root.join('db', 'seed_data', 'merchants.csv') +puts "Loading raw merchant data from #{MERCHANT_FILE}" + +merchant_failures = [] +CSV.foreach(MERCHANT_FILE, :headers => true) do |row| + merchant = Merchant.new + merchant.username = row['username'] + merchant.email = row['email'] + puts "Created merchant: #{merchant.inspect}" + successful = merchant.save + if !successful + merchant_failures << merchant + end +end + +puts "Added #{Merchant.count} merchant records" +puts "#{merchant_failures.length} merchants failed to save" + + + +PRODUCT_FILE = Rails.root.join('db', 'seed_data', 'products.csv') +puts "Loading raw product data from #{PRODUCT_FILE}" + +product_failures = [] +CSV.foreach(PRODUCT_FILE, :headers => true) do |row| + product = Product.new + product.merchant_id = row['merchant_id'] + product.name = row['name'] + product.price = row['price'] + product.quantity_avail = row['quantity_avail'] + puts "Created product: #{product.inspect}" + successful = product.save + if !successful + product_failures << product + end +end + +puts "Added #{Product.count} product records" +puts "#{product_failures.length} products failed to save" + +CATEGORY_FILE = Rails.root.join('db', 'seed_data', 'categories.csv') +puts "Loading raw category data from #{CATEGORY_FILE}" + +category_failures = [] +CSV.foreach(CATEGORY_FILE, :headers => true) do |row| + category = Category.new + category.name = row['name'] + puts "Created category: #{category.inspect}" + successful = category.save + if !successful + category_failures << category + end +end + +puts "Added #{Category.count} category records" +puts "#{category_failures.length} categories failed to save" + + +# Since we set the primary key (the ID) manually on each of the +# tables, we've got to tell postgres to reload the latest ID +# values. Otherwise when we create a new record it will try +# to start at ID 1, which will be a conflict. +puts "Manually resetting PK sequence on each table" +ActiveRecord::Base.connection.tables.each do |t| + ActiveRecord::Base.connection.reset_pk_sequence!(t) +end + +puts "done" diff --git a/lib/assets/.keep b/lib/assets/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/tasks/.keep b/lib/tasks/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/log/.keep b/log/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/package.json b/package.json new file mode 100644 index 0000000000..f874acf437 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "name": "betsy", + "private": true, + "dependencies": {} +} diff --git a/public/404.html b/public/404.html new file mode 100644 index 0000000000..2be3af26fc --- /dev/null +++ b/public/404.html @@ -0,0 +1,67 @@ + + + + The page you were looking for doesn't exist (404) + + + + + + +
+
+

The page you were looking for doesn't exist.

+

You may have mistyped the address or the page may have moved.

+
+

If you are the application owner check the logs for more information.

+
+ + diff --git a/public/422.html b/public/422.html new file mode 100644 index 0000000000..c08eac0d1d --- /dev/null +++ b/public/422.html @@ -0,0 +1,67 @@ + + + + The change you wanted was rejected (422) + + + + + + +
+
+

The change you wanted was rejected.

+

Maybe you tried to change something you didn't have access to.

+
+

If you are the application owner check the logs for more information.

+
+ + diff --git a/public/500.html b/public/500.html new file mode 100644 index 0000000000..78a030af22 --- /dev/null +++ b/public/500.html @@ -0,0 +1,66 @@ + + + + We're sorry, but something went wrong (500) + + + + + + +
+
+

We're sorry, but something went wrong.

+
+

If you are the application owner check the logs for more information.

+
+ + diff --git a/public/apple-touch-icon-precomposed.png b/public/apple-touch-icon-precomposed.png new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000000..37b576a4a0 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1 @@ +# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file diff --git a/public/system/products/photos/000/000/011/original/awkward-seal.jpg b/public/system/products/photos/000/000/011/original/awkward-seal.jpg new file mode 100644 index 0000000000..32143cc420 Binary files /dev/null and b/public/system/products/photos/000/000/011/original/awkward-seal.jpg differ diff --git a/public/system/products/photos/000/000/011/original/talisman.jpeg b/public/system/products/photos/000/000/011/original/talisman.jpeg new file mode 100644 index 0000000000..3dea65ed91 Binary files /dev/null and b/public/system/products/photos/000/000/011/original/talisman.jpeg differ diff --git a/public/system/products/photos/000/000/012/original/batman-approves.png b/public/system/products/photos/000/000/012/original/batman-approves.png new file mode 100644 index 0000000000..cc8add813d Binary files /dev/null and b/public/system/products/photos/000/000/012/original/batman-approves.png differ diff --git a/public/system/products/photos/000/000/012/original/brooms.jpg b/public/system/products/photos/000/000/012/original/brooms.jpg new file mode 100644 index 0000000000..0ec06f1c4d Binary files /dev/null and b/public/system/products/photos/000/000/012/original/brooms.jpg differ diff --git a/public/system/products/photos/000/000/012/original/cheesegrater.jpeg b/public/system/products/photos/000/000/012/original/cheesegrater.jpeg new file mode 100644 index 0000000000..5101bd5e1d Binary files /dev/null and b/public/system/products/photos/000/000/012/original/cheesegrater.jpeg differ diff --git a/public/system/products/photos/000/000/013/original/poison.jpeg b/public/system/products/photos/000/000/013/original/poison.jpeg new file mode 100644 index 0000000000..a7784f25e1 Binary files /dev/null and b/public/system/products/photos/000/000/013/original/poison.jpeg differ diff --git a/public/system/products/photos/000/000/013/original/rubberduck.gif b/public/system/products/photos/000/000/013/original/rubberduck.gif new file mode 100644 index 0000000000..626e516f8d Binary files /dev/null and b/public/system/products/photos/000/000/013/original/rubberduck.gif differ diff --git a/public/system/products/photos/000/000/013/original/spooky_salt.jpeg b/public/system/products/photos/000/000/013/original/spooky_salt.jpeg new file mode 100644 index 0000000000..da0cb7121a Binary files /dev/null and b/public/system/products/photos/000/000/013/original/spooky_salt.jpeg differ diff --git a/public/system/products/photos/000/000/014/original/ivan-mityaev-skull-front.jpg b/public/system/products/photos/000/000/014/original/ivan-mityaev-skull-front.jpg new file mode 100644 index 0000000000..a2ffe77cf9 Binary files /dev/null and b/public/system/products/photos/000/000/014/original/ivan-mityaev-skull-front.jpg differ diff --git a/public/system/products/photos/000/000/014/original/pizza_rat.png b/public/system/products/photos/000/000/014/original/pizza_rat.png new file mode 100644 index 0000000000..99990edd71 Binary files /dev/null and b/public/system/products/photos/000/000/014/original/pizza_rat.png differ diff --git a/public/system/products/photos/000/000/015/original/brain.jpg b/public/system/products/photos/000/000/015/original/brain.jpg new file mode 100644 index 0000000000..4b9b668cbd Binary files /dev/null and b/public/system/products/photos/000/000/015/original/brain.jpg differ diff --git a/public/system/products/photos/000/000/015/original/download.jpeg b/public/system/products/photos/000/000/015/original/download.jpeg new file mode 100644 index 0000000000..0d15ab0f0d Binary files /dev/null and b/public/system/products/photos/000/000/015/original/download.jpeg differ diff --git a/public/system/products/photos/000/000/015/original/pizza_rat.png b/public/system/products/photos/000/000/015/original/pizza_rat.png new file mode 100644 index 0000000000..99990edd71 Binary files /dev/null and b/public/system/products/photos/000/000/015/original/pizza_rat.png differ diff --git a/public/system/products/photos/000/000/021/original/brain.jpg b/public/system/products/photos/000/000/021/original/brain.jpg new file mode 100644 index 0000000000..4b9b668cbd Binary files /dev/null and b/public/system/products/photos/000/000/021/original/brain.jpg differ diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb new file mode 100644 index 0000000000..d19212abd5 --- /dev/null +++ b/test/application_system_test_case.rb @@ -0,0 +1,5 @@ +require "test_helper" + +class ApplicationSystemTestCase < ActionDispatch::SystemTestCase + driven_by :selenium, using: :chrome, screen_size: [1400, 1400] +end diff --git a/test/controllers/.keep b/test/controllers/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/controllers/categories_controller_test.rb b/test/controllers/categories_controller_test.rb new file mode 100644 index 0000000000..cbda04c938 --- /dev/null +++ b/test/controllers/categories_controller_test.rb @@ -0,0 +1,81 @@ +require "test_helper" + +describe CategoriesController do + describe "index" do + it "should successfully get to categories index page" do + get categories_path + must_respond_with :success + end + + it "succeeds when there are no categories" do + Category.destroy_all + get categories_path + must_respond_with :success + end + end + + describe "new" do + it "should successfully get new page" do + get new_category_path + must_respond_with :success + end + end + + describe "create" do + it "should be able to create a new category" do + post categories_path, params: {category: {name: "creepy things"}} + must_respond_with :redirect + must_redirect_to category_path(Category.last.id) + + proc { + post categories_path, params: {category: {name: "other creepy things"}} + }.must_change 'Category.count', 1 + end + + it "does not change category count if invalid category is entered" do + count = Category.count + + post categories_path, params: {category: {name: "super duper extra fancy creepy things"}} + must_respond_with :bad_request + + Category.count.must_equal count + end + end + + describe "show" do + it "should successfully get to category show page" do + get category_path(Category.first.id) + must_respond_with :success + end + + it "renders 404 not_found when you try to show an invalid category " do + bad = Category.last.id + 1 + get category_path(bad) + must_respond_with :not_found + end + end + + + describe "destroy" do + it "should successfully delete category" do + delete category_path(categories(:brooms).id) + must_respond_with :redirect + must_redirect_to categories_path + + proc { + delete category_path(categories(:cauldrons).id) + }.must_change 'Category.count', -1 + end + + + it "renders 404 not_found and does not update the DB for a bogus category ID" do + start_count = Category.count + + bad = Category.last.id + 1 + delete category_path(bad) + must_respond_with :not_found + + Category.count.must_equal start_count + 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..b90986b374 --- /dev/null +++ b/test/controllers/merchants_controller_test.rb @@ -0,0 +1,118 @@ +require "test_helper" + +describe MerchantsController do + + describe "#index" do + it "should respond with success when there are many merchants" do + Merchant.count.must_be :>, 0 + get merchants_path + must_respond_with :success + end + + it "should succeed with no merchants" do + Product.destroy_all + Merchant.destroy_all + + get merchants_path + must_respond_with :success + end + end + + describe "#show" do + it "should succeed with an existing merchant" do + get merchant_path(Merchant.first) + must_respond_with :success + end + + it "renders 404 not_found when you try to show an invalid merchant" do + bad = Merchant.last.id + 1 + get merchant_path(bad) + must_respond_with :not_found + end + end + + describe "#new" do + it "should successfully get new page" do + get new_merchant_path + must_respond_with :success + end + end + + # describe "edit" do + # it "succeeds for an existing merchant" do + # get edit_merchant_path(Merchant.first) + # must_respond_with :success + # end + # + # it "returns an error for a non-existant ID" do + # # no_merchant_id = Merchant.last.id + 1 + # get edit_merchant_path(100) + # must_respond_with :failure + # end + # end + # + # describe "update" do + # it "succeeds for valid data and an existing ID" do + # merchant = Merchant.first + # merchant_data = { + # merchant: { + # email: merchant.email + " addition" + # } + # } + # + # patch merchant_path(merchant), params: merchant_data + # must_redirect_to merchant_path(merchant) + # + # Merchant.find(merchant.id).email.must_equal merchant_data[:merchant][:email] + # end + # + # it "renders the form for bad data" do + # merchant = Merchant.first + # merchant_data = { + # merchant: { + # email: "" + # } + # } + # + # patch merchant_path(merchant), params: merchant_data + # must_respond_with :success + # + # Merchant.find(merchant.id).email.must_equal merchant.email + # end + # end + # + # describe "destroy" do + # it "succeeds for an existing id" do + # # merchant_id = Merchant.first.id + # # + # # delete merchant_path(merchant_id) + # # must_redirect_to root_path + # + # delete merchant_path(merchants(:ghosty).id) + # must_respond_with :redirect + # must_redirect_to root_path + # + # Merchant.find_by(id: merchants(:ghosty)).must_be_nil + # end + # end + + describe "when authenticated" do + let(:merchant) { merchants(:ada) } + + it "should allow a merchant to view its own orders page" do + merchant = merchants(:ada) + login(merchant) + get merchant_orders_path(merchants(:ada).id) + must_respond_with :success + end + + it "should not allow merchants to view other merchants orders page" do + merchant = merchants(:ada) + login(merchant) + get merchant_orders_path(merchants(:spooky).id) + must_respond_with :redirect + must_redirect_to home_path + flash.keys.must_include "result_text" + 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..e1909466e5 --- /dev/null +++ b/test/controllers/orders_controller_test.rb @@ -0,0 +1,219 @@ +require "test_helper" +#TODO Look at update test that is commented out + +describe OrdersController do + + describe "index" do + it "succeeds when there are orders" do + Order.count.must_be :>, 0, "No works in the test fixtures" + get orders_path + must_respond_with :success + end + + it "succeeds when there are no orders" do + Order.destroy_all + get orders_path + must_respond_with :success + end + + it "succeeds when there are orders with a given status" do + get orders_path, params: {status: "pending"} + must_respond_with :success + end + + it "succeeds when there are no orders with a given status" do + get orders_path, params: {status: "nothing has this status"} + must_respond_with :success + end + + end + + describe "new" do + it "works" do + get new_order_path + must_respond_with :success + end + end + + describe "create" do + it "creates an order with a status of pending" do + #Arrange: nothing to arrange for the creation. Will always start with status of pending and all other values as nil + start_count = Order.count + #Act + post orders_path + #Assert + Order.count.must_equal start_count + 1 + Order.last.status.must_equal "pending" + end + + it "sets the session[:order_id] to the id of the created order" do + post orders_path + session[:order_id].wont_equal nil + session[:order_id].must_equal Order.last.id + end + end + + describe "show" do + setup { session_setup } + + before do + @order = Order.find_by(id: session[:order_id]) + end + + it "succeeds for an existing order" do + get order_path(@order.id) + must_respond_with :success + end + + it "renders 404 not_found for a bogus order ID" do + @order.destroy + get order_path(@order.id) + must_respond_with :not_found + end + end + + describe "edit" do + setup { session_setup } + + before do + @order = Order.find_by(id: session[:order_id]) + end + + it "succeeds for an existing order" do + get edit_order_path(@order.id) + must_respond_with :success + end + + it "allows edits to a complete order" do + @order.status = "complete" + @order.save + get edit_order_path(@order.id) + must_respond_with :success + end + + it "does not allow edits to a shipped order" do + @order.status = "shipped" + @order.save + get edit_order_path(@order.id) + must_redirect_to home_path + end + + it "renders 404 not_found for a bogus order ID" do + @order.destroy + get edit_order_path(@order.id) + must_respond_with :not_found + end + end + + describe "update" do + setup { session_setup } + + before do + @order = Order.find_by(id: session[:order_id]) + end + + it "succeeds for valid data and an existing order ID" do + order_data = { + order: { + email: "buyer@email.com", + address: "100 Witchy Way", + city: "Seattle", + state: "Washington", + name: "Gale", + card_number: 1234123412341234, + card_exp: "Sun, 1 Oct 2017", + card_cvv: 546, + zip_code: "98122" + } + } + patch order_path(@order.id), params: order_data + must_redirect_to order_confirm_order_path(@order.id) + + # Verify the DB was really modified + Order.find(@order.id).status.must_equal "complete" + end + + it "resets the session[:order_id] to nil when order is complete" do + order_data = { + order: { + email: "buyer@email.com", + address: "100 Witchy Way", + city: "Seattle", + state: "Washington", + name: "Gale", + card_number: 1234123412341234, + card_exp: "Sun, 1 Oct 2017", + card_cvv: 546, + zip_code: "98122" + } + } + + patch order_path(@order.id), params: order_data + + session[:order_id].must_equal nil + end + + it "renders bad_request for insufficient buyer data and does not change status to complete" do + order_data = { + order: { + email: nil, + address: "100 Witchy Way", + city: "Seattle", + state: "Washington", + name: "Gale", + card_number: 1234123412341234, + card_exp: "Sun, 1 Oct 2017", + card_cvv: 546, + zip_code: "98122" + } + } + + patch order_path(@order.id), params: order_data + must_respond_with :bad_request + + # Verify the DB was not modified + Order.find(@order.id).status.must_equal "pending" + end + + it "renders 404 not_found for a bogus order ID" do + order_data = { + order: { + email: "buyer@email.com", + address: "100 Witchy Way", + city: "Seattle", + state: "Washington", + name: "Gale", + card_number: 1234123412341234, + card_exp: "Sun, 1 Oct 2017", + card_cvv: 546, + zip_code: "98122" + } + } + + @order.destroy + get order_path(@order.id), params: order_data + must_respond_with :not_found + end + + it "does not allow changes to an order with the status of shipped" do + #can't initialize a session with an order that has the shipped status + end + end + describe "#shipped" do + + setup { session_setup } + + before do + @order = Order.find_by(id: session[:order_id]) + end + + it "Allow the merchant to change an order's status from complete to shipped" do + proc { patch ship_order_path(orders(:order_one)) } + must_respond_with :success + end + it "Doesn't allow the merchant to change an order's status to shipped FROM pending" do + patch ship_order_path(@order.id) + must_redirect_to home_path + end + end +end diff --git a/test/controllers/products_controller_test.rb b/test/controllers/products_controller_test.rb new file mode 100644 index 0000000000..28eaf00ec9 --- /dev/null +++ b/test/controllers/products_controller_test.rb @@ -0,0 +1,226 @@ +require "test_helper" + +describe ProductsController do + + describe 'root path' do + it "successfully navigates to root path" do + get root_path + must_respond_with :success + end + end + + describe 'index' do + it "succeeds when there are products" do + get products_path + must_respond_with :success + end + + it "succeeds when there are no products" do + Product.destroy_all + get products_path + must_respond_with :success + end + + end + + describe "new" do + it "works" do + get new_product_path + must_respond_with :success + end + end + + describe "create" do + let(:merchant) { merchants(:ada) } + + it "creates a new product" do + merchant = merchants(:ada) + login(merchant) + proc { + post products_path, params: { product: { name: "eyeballs", quantity_avail: 4, price: 9.99}, merchant_id: merchant.id} + }.must_change 'Product.count', 1 + end + + it "fails when missing params" do + merchant = merchants(:ada) + login(merchant) + proc { + post products_path, params: { product: { name: "", quantity_avail: 4, price: 9.99}, merchant_id: merchant.id} + }.must_change 'Product.count', 0 + end + end + + describe "show" do + it "succeeds for an existing product" do + get product_path(Product.first) + must_respond_with :success + end + + it "renders 404 not_found for a bogus product ID" do + fake = Product.last.id + 1 + get product_path(fake) + must_respond_with :not_found + end + end + # + describe "edit" do + it "succeeds for an existing product" do + get edit_product_path(Product.first) + must_respond_with :success + end + + end + + describe "#add_product_to_cart" do + setup { session_setup } + + it "should add in-stock products to the pending order" do + patch add_product_path(products(:pointy_hat).id) + must_respond_with :redirect + + end + + it "should not add out-of-stock products to pending order" do + patch add_product_path(products(:out_of_stock).id) + must_respond_with :redirect + + end + + it "can add the same product multiple times when in stock" do + patch add_product_path(products(:pointy_hat).id) + patch add_product_path(products(:pointy_hat).id) + + order = Order.find_by(id: session[:order_id]) + order.products.size.must_equal 2 + + order.products.each do |prod| + prod.name.must_equal "Pointy Hat" + end + end + + it "changes the product quantity if successful" do + product = products(:pointy_hat) + product.quantity_avail.must_equal 5 + + patch add_product_path(product.id) + patch add_product_path(product.id) + + + Product.find(products(:pointy_hat).id).quantity_avail.must_equal 3 + end + + end + + describe "remove_product_from_cart" do + setup { session_setup } + + before do + patch add_product_path(products(:pointy_hat).id) + patch add_product_path(products(:pointy_hat).id) + @order = Order.find_by(id: session[:order_id]) + end + + it "should remove exactly one instance of product from the order if at least one instance is in order" do + @order.products.size.must_equal 2 + + patch remove_product_path(products(:pointy_hat).id) + @order.products.size.must_equal 1 + end + + it "adds one product back to quantity_avail if successfully removed from order" do + Product.find(products(:pointy_hat).id).quantity_avail.must_equal 3 + + patch remove_product_path(products(:pointy_hat).id) + + Product.find(products(:pointy_hat).id).quantity_avail.must_equal 4 + + end + + it "should not change order.products if product not there" do + patch remove_product_path(products(:not_in_order).id) + @order.products.size.must_equal 2 + + end + + it "should not change quantity of product available if not successful" do + Product.find(products(:not_in_order).id).quantity_avail.must_equal 5 + + patch remove_product_path(products(:not_in_order).id) + + Product.find(products(:not_in_order).id).quantity_avail.must_equal 5 + end + + + end + + + describe "update" do + let(:merchant) { merchants(:ada) } + it "update an existant product" do + merchant = merchants(:ada) + login(merchant) + product = Product.find(products(:invisible_hat).id) + product_data = { + product: { + name: product.name + "more text" + } + } + + patch product_path(product), params: product_data + must_redirect_to merchant_products_path(session[:user_id]) + + + Product.find(product.id).name.must_equal product_data[:product][:name] + end + end + + describe "delete" do + it "should successfully delete product" do + delete product_path(products(:pointy_hat).id) + must_respond_with :redirect + must_redirect_to products_path + + proc { + delete product_path(products(:out_of_stock).id) + }.must_change 'Product.count', -1 + end + + it "renders 404 not_found and does not update the DB for a bogus product ID" do + start_count = Product.count + + bad = Product.last.id + 1 + delete product_path(bad) + must_respond_with :not_found + + Product.count.must_equal start_count + + end + end + + describe "product by category" do + it "should get products by category" do + get category_products_path(categories(:brooms).id) + must_respond_with :success + end + + it "should render 404 if category does not exist" do + bad = Category.last.id + 1 + get category_products_path(bad) + must_respond_with :not_found + end + end + + describe "products by merchant" do + it "should show products belonging to a specific merchant" do + get merchant_products_path(merchants(:witch).id) + must_respond_with :success + end + + it "should render 404 if merchant does not exist" do + bad = Merchant.last.id + 1 + get merchant_products_path(bad) + must_respond_with :not_found + 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..52a1659433 --- /dev/null +++ b/test/controllers/reviews_controller_test.rb @@ -0,0 +1,40 @@ +require "test_helper" + +describe ReviewsController do + + describe "new" do + it "reviews" do + get new_product_review_path(:product_id=>products(:pointy_hat).id) + must_respond_with :success + end + end + + describe "create" do + let(:merchant) { merchants(:spooky) } + + it "should be able to create a review" do + proc{ + post product_reviews_path(products(:sad_hat).id), params: {review: {rating: 3, text_review: "Smokin."} } + }.must_change 'Review.count', 1 + + must_respond_with :redirect + must_redirect_to product_path(Review.last.product_id) + end + + it "should rerender the form if it can't create the review" do + proc { + post product_reviews_path(products(:sad_hat).id), params: { review: {rating: nil, text_review: "Smokin.", product_id: products(:pointy_hat).id} } + }.must_change 'Review.count', 0 + + must_respond_with :bad_request + end + + it "should prevent a merchant from creating a review on its products" do + merchant = merchants(:spooky) + login(merchant) + proc { + post product_reviews_path(products(:sad_hat).id), params: { review: {rating: 4, text_review: "buy this hat!", product_id: products(:sad_hat).id} } + }.must_change 'Review.count', 0 + 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..1e4c1093c3 --- /dev/null +++ b/test/controllers/sessions_controller_test.rb @@ -0,0 +1,59 @@ +require "test_helper" + +describe SessionsController do + let(:merchant) { merchants(:ada) } + + describe "auth_callback" do + it "logs in an existing merchant and redirects to home path" do + login(merchant) + must_redirect_to home_path + session[:user_id].must_equal merchant.id + flash[:result_text].must_include "Welcome back" + end + + it "does not change merchant count for existing merchant" do + proc { + login(merchants(:grace)) + }.wont_change "Merchant.count" + end + + it "creates a new merchant if you have never logged in before" do + merchant = Merchant.new(provider: :github, username: 'Ada', email: 'ada@adadev.org', uid: 999) + + login(merchant) + must_respond_with :redirect + must_redirect_to home_path + + session[:user_id].must_equal Merchant.last.id + end + + it "should not create a new merchant on repeat logins" do + proc { + 3.times do + login(merchant) + end + }.wont_change "Merchant.count" + end + + end + + describe "logout path" do + it "logs a user out" do + merchant = merchants(:grace) + login(merchant) + session[:user_id].must_equal merchant.id + + post logout_path + must_redirect_to home_path + session[:user_id].must_equal nil + end + + it "does not have a user id if you are logged out" do + merchant = merchants(:ada) + login(merchant) + + post logout_path + session[:user_id].must_equal nil + 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..24867a6cea --- /dev/null +++ b/test/fixtures/categories.yml @@ -0,0 +1,5 @@ +brooms: + name: custom brooms + +cauldrons: + name: bronzed cauldrons diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/fixtures/merchants.yml b/test/fixtures/merchants.yml new file mode 100644 index 0000000000..96cecf4092 --- /dev/null +++ b/test/fixtures/merchants.yml @@ -0,0 +1,31 @@ +spooky: + provider: github + uid: 11234 + username: Spooky Books + email: mailing@email.com + +ghosty: + provider: github + uid: 334455 + username: Ghost Artifacts + email: letters@webmail.com + +toady: + username: Toads Are We + email: toadsareanimalstoo@mail.com + +witch: + username: witch + email: witch@merchants.com + +ada: + provider: github + uid: 12345 + email: ada@adadevelopersacademy.org + username: countess_ada + +grace: + provider: github + uid: 13371337 + email: grace@hooper.net + username: graceful_hoops diff --git a/test/fixtures/orders.yml b/test/fixtures/orders.yml new file mode 100644 index 0000000000..1dd558804f --- /dev/null +++ b/test/fixtures/orders.yml @@ -0,0 +1,49 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +# This model initially had no columns defined. If you add columns to the +# model remove the "{}" from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below +# +pending_order: + status: pending + email: nil + address: nil + name: nil + card_number: nil + card_exp: nil + card_cvv: nil + zip_code: nil + +order_one: + status: complete + email: me@mail.com + address: 111 Main Street + name: Martha Stewart + card_number: 1234567890987654 + card_exp: Sun, 1 Oct 2017 + card_cvv: 546 + zip_code: 98115 + city: Scranton + state: PA + +almost_there_order: + status: pending + email: buyer@email.com + address: 100 Witchy Way, Seattle, WA + name: Gale + card_number: 1234 1234 1234 1234 + card_exp: 01/21 + card_cvv: "546" + zip_code: "98122" + +shipped_order: + status: shipped + email: me@mail.com + address: 111 Main Street + name: Martha Stewart + card_number: 1234567890987654 + card_exp: Sun, 1 Oct 2017 + card_cvv: 546 + zip_code: 98115 + city: Scranton + state: PA diff --git a/test/fixtures/products.yml b/test/fixtures/products.yml new file mode 100644 index 0000000000..21fcbd2500 --- /dev/null +++ b/test/fixtures/products.yml @@ -0,0 +1,53 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +# This model initially had no columns defined. If you add columns to the +# model remove the "{}" from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below +# +pointy_hat: + name: "Pointy Hat" + price: 9.99 + quantity_avail: 5 + merchant: spooky + + +sad_hat: + name: "Sad Hat" + price: 8.99 + quantity_avail: 10 + merchant: spooky + + + +missing_name: + name: + price: 9.99 + quantity_avail: 5 + merchant: ghosty + + + +out_of_stock: + name: "Nopes" + price: 4.99 + quantity_avail: 0 + merchant: ghosty + +not_in_order: + name: "not there" + price: 9.99 + quantity_avail: 5 + merchant: spooky + +available: + name: "Not selling" + price: 30.33 + quantity_avail: 3 + merchant: spooky + available: "Retired" + +invisible_hat: + name: "Magic Beans" + price: 3.00 + quantity_avail: 5 + merchant: ada diff --git a/test/fixtures/reviews.yml b/test/fixtures/reviews.yml new file mode 100644 index 0000000000..f0e6578f6e --- /dev/null +++ b/test/fixtures/reviews.yml @@ -0,0 +1,10 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +# This model initially had no columns defined. If you add columns to the +# model remove the "{}" from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below +# +reviewer: + product_id: 1 + rating: 5 + text_review: "Such good smoke. Yes. <3" 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..3167030870 --- /dev/null +++ b/test/models/category_test.rb @@ -0,0 +1,55 @@ +require "test_helper" + +describe Category do + let(:category) {Category.new} + let(:brooms) {categories(:brooms)} + let(:cauldrons) {categories(:cauldrons)} + + + describe "validations" do + it "must have a category name to be valid" do + brooms.valid?.must_equal true + brooms.name = nil + brooms.valid?.must_equal false + end + + it "requires a unique category name" do + category1 = Category.new(name: "category") + category1.save! + + category2 = Category.new(name: "category") + result = category2.save + result.must_equal false + category2.errors.messages.must_include :name + end + + it "must not have a category name of more than 25 characters" do + category = Category.new(name: "various colored sheets for ghosts") + category.valid?.must_equal false + + category2 = Category.new(name: "ghost sheets") + category2.valid?.must_equal true + end + end + + describe "relations" do + it "has a list of products in it" do + category = categories(:brooms) + product = products(:pointy_hat) + + category.must_respond_to :products + + category.products.count.must_equal 0 + category.products << product + category.products.count.must_equal 1 + end + + it "product responds with an empty collection if it has no assigned categories" do + category = Category.create(name: "Nothing to see here") + + category.must_respond_to :products + category.products.count.must_equal 0 + end + end + +end diff --git a/test/models/merchant_test.rb b/test/models/merchant_test.rb new file mode 100644 index 0000000000..4a3693e2e5 --- /dev/null +++ b/test/models/merchant_test.rb @@ -0,0 +1,55 @@ +require "test_helper" + +describe Merchant do + + let(:merchant) {Merchant.new} + let(:spooky) {merchants(:spooky)} + let(:ghosty) {merchants(:ghosty)} + + describe "validations" do + + it "must have a merchant name to be valid" do + spooky.valid?.must_equal true + spooky.username = nil + spooky.valid?.must_equal false + end + + it "must have a merchant email to be valid" do + spooky.valid?.must_equal true + spooky.email = nil + spooky.valid?.must_equal false + end + + it "requires a unique merchant username" do + username = "Ghouls Are Us" + email1 = "ghosts@gmail.com" + email2 = "sweepsthebroom@gmail.com" + merchant1 = Merchant.new(username: username, email: email1) + merchant1.save! + + merchant2 = Merchant.new(username: username, email: email2) + result = merchant2.save + result.must_equal false + merchant2.errors.messages.must_include :username + end + + it "requires a unique merchant email" do + username1 = "Ghouls Are Us" + username2 = "Spooky Woods" + email = "ghosts@gmail.com" + merchant1 = Merchant.new(username: username1, email: email) + merchant1.save! + + merchant2 = Merchant.new(username: username2, email: email) + result = merchant2.save + result.must_equal false + merchant2.errors.messages.must_include :email + end + end + + describe "relationships" do + it "sets the merchant through merchant" do + + end + end +end diff --git a/test/models/order_test.rb b/test/models/order_test.rb new file mode 100644 index 0000000000..b9e646eefd --- /dev/null +++ b/test/models/order_test.rb @@ -0,0 +1,227 @@ +require "test_helper" + +describe Order do + let(:order) { Order.new } + let(:order_one) { orders(:order_one) } + + describe "relations" do + it "has many products" do + order1 = orders(:order_one) + product = products(:pointy_hat) + + order1.must_respond_to :products + + order1.products << product + order1.products.count.must_equal 1 + order1.products << product + order1.products.count.must_equal 2 + end + + it "belongs to many products" do + order1 = orders(:pending_order) + order2 = orders(:almost_there_order) + product = products(:pointy_hat) + + order1.products << product + order2.products << product + + product.must_respond_to :orders + product.orders.count.must_equal 2 + end + end + + describe "validations" do + it "must have a valid status to be true" do + order_one.valid?.must_equal true + order_one.status = "incomplete" + order_one.valid?.must_equal false + end + + it "must have a status to be valid" do + order_one.valid?.must_equal true + order_one.status = nil + order_one.valid?.must_equal false + order_one.errors.messages.must_include :status + + order_one.status = " " + order_one.valid?.must_equal false + order_one.errors.messages.must_include :status + end + + it "must have a valid email address to be true" do + order_one.valid?.must_equal true + order_one.email = "abcdefg" + order_one.valid?.must_equal false + end + + it "must have an email address to be valid" do + order_one.valid?.must_equal true + order_one.email = nil + order_one.valid?.must_equal false + order_one.errors.messages.must_include :email + + order_one.email = " " + order_one.valid?.must_equal false + order_one.errors.messages.must_include :email + end + + it "must have a street address to be valid" do + order_one.valid?.must_equal true + order_one.address = nil + order_one.valid?.must_equal false + order_one.errors.messages.must_include :address + + order_one.address = " " + order_one.valid?.must_equal false + order_one.errors.messages.must_include :address + end + + it "must have a name to be valid" do + order_one.valid?.must_equal true + order_one.name = nil + order_one.valid?.must_equal false + order_one.errors.messages.must_include :name + end + + it "must have a valid card number to be true" do + order_one.valid?.must_equal true + order_one.card_number = 1234567 + order_one.valid?.must_equal false + + order_one.card_number = "not a number" + order_one.valid?.must_equal false + + order_one.card_number = 12345678909876543 + order_one.valid?.must_equal false + end + + it "must have a card number to be valid" do + order_one.valid?.must_equal true + order_one.card_number = nil + order_one.valid?.must_equal false + order_one.errors.messages.must_include :card_number + end + + it "must have a valid expiration date to be true" do + order_one.valid?.must_equal true + order_one.card_exp = "March 9, 2017" + order_one.valid?.must_equal true + + order_one.card_exp = "10/2018" + order_one.valid?.must_equal false + order_one.errors.messages.must_include :card_exp + + order_one.card_exp = "March 2017" + order_one.valid?.must_equal false + order_one.errors.messages.must_include :card_exp + end + + it "must have an expiration date to be valid" do + order_one.valid?.must_equal true + order_one.card_exp = nil + order_one.valid?.must_equal false + end + + it "must have a valid card cvv to be true" do + order_one.valid?.must_equal true + order_one.card_cvv = "nine" + order_one.valid?.must_equal false + + order_one.card_cvv = 12 + order_one.valid?.must_equal false + + order_one.card_cvv = 1234 + order_one.valid?.must_equal false + end + + it "must have a card cvv to be valid" do + order_one.valid?.must_equal true + order_one.card_cvv = nil + order_one.valid?.must_equal false + order_one.errors.messages.must_include :card_cvv + + order_one.card_cvv = " " + order_one.valid?.must_equal false + order_one.errors.messages.must_include :card_cvv + end + + it "must have a valid zip code to be true" do + order_one.valid?.must_equal true + order_one.zip_code = 9812500000 + order_one.valid?.must_equal false + + order_one.zip_code = 9812 + order_one.valid?.must_equal false + + order_one.zip_code = "98125-" + order_one.valid?.must_equal false + end + + it "must have a zip code to be valid" do + order_one.valid?.must_equal true + order_one.zip_code = nil + order_one.valid?.must_equal false + order_one.errors.messages.must_include :zip_code + + order_one.zip_code = " " + order_one.valid?.must_equal false + order_one.errors.messages.must_include :zip_code + end + + it "must have a city to be valid" do + order_one.valid?.must_equal true + order_one.city = nil + order_one.valid?.must_equal false + order_one.errors.messages.must_include :city + + order_one.city = " " + order_one.valid?.must_equal false + order_one.errors.messages.must_include :city + end + + it "must have a state to be valid" do + order_one.valid?.must_equal true + order_one.state = nil + order_one.valid?.must_equal false + order_one.errors.messages.must_include :state + + order_one.state = " " + order_one.valid?.must_equal false + order_one.errors.messages.must_include :state + end + end + + describe "shipped" do + it "returns true if the order has a status of shipped" do + orders(:shipped_order).shipped.must_equal true + end + it "returns false if the order does not have a status of shipped" do + orders(:pending_order).shipped.must_equal false + end + end + + describe "completed?" do + it "returns true if the order has a status of complete" do + orders(:order_one).completed?.must_equal true + end + it "returns false if the order does not have a status of complete" do + orders(:pending_order).shipped.must_equal false + end + end + + describe "order_total" do + it "returns an accurate sum of the prices of the products connected to the order" do + order = orders(:pending_order) + product1 = products(:pointy_hat) + product2 = products(:sad_hat) + + order.order_total.must_equal 0 + order.products << product1 + order.order_total.must_equal 9.99 + order.products << product1 + order.order_total.must_equal (9.99 * 2) + order.products << product2 + order.order_total.must_equal (9.99 * 2) + 8.99 + end + end +end diff --git a/test/models/product_test.rb b/test/models/product_test.rb new file mode 100644 index 0000000000..6bb9259500 --- /dev/null +++ b/test/models/product_test.rb @@ -0,0 +1,167 @@ +require "test_helper" + +describe Product do + + describe "validations" do + it "requires a name" do + products(:pointy_hat).merchant = Merchant.first + products(:pointy_hat).save + products(:pointy_hat).valid?.must_equal true + + + products(:missing_name).merchant = Merchant.first + products(:missing_name).save + products(:missing_name).valid?.must_equal false + + products(:missing_name).name = "Another pointy hat" + products(:missing_name).save + products(:missing_name).valid?.must_equal true + end + + it "requires a price" do + test = Product.new(name: "Caldroun", quantity_avail: 1, merchant: Merchant.first) + test.valid?.must_equal false + + test.price = 59.99 + test.valid?.must_equal true + end + + it "requires a price that is a number" do + test = Product.new(name: "Caldroun", quantity_avail: 1, price: "cats", merchant: Merchant.first) + test.valid?.must_equal false + end + + it "requires a price that is greater than 0" do + test = Product.new(name: "Caldroun", quantity_avail: 1, price: -2.50, merchant: Merchant.first) + test.valid?.must_equal false + + another = Product.new(name: "Caldroun", quantity_avail: 1, price: 0, merchant: Merchant.first) + another.valid?.must_equal false + end + + it "requires a quantity_avail" do + test = Product.new(name: "Caldroun", price: 68.50, merchant: Merchant.first) + test.valid?.must_equal false + + test.quantity_avail = 1 + test.valid?.must_equal true + end + + it "can have a quantity_avail of 0" do + test = Product.new(name: "Caldroun", quantity_avail: 0, price: 68.50, merchant: Merchant.first) + test.valid?.must_equal true + end + + it "cannot have a quantity_avail less than 0" do + test = Product.new(name: "Caldroun", quantity_avail: -1, price: 68.50, merchant: Merchant.first) + test.valid?.must_equal false + end + end + + describe "relations" do + it "has a merchant" do + test = Product.create(name: "Caldroun", quantity_avail: 5, price: 68.50, merchant: Merchant.first) + test.merchant.must_equal Merchant.first + + test.merchant.id.must_equal Merchant.first.id + end + + it "cannot exist without a merchant" do + test = Product.create(name: "Caldroun", quantity_avail: 5, price: 68.50, merchant: nil) + + assert_nil(test.merchant, msg = nil) + assert_nil(test.id, msg = nil) + end + + it "has reviews" do + test = Product.create(name: "Caldroun", quantity_avail: 5, price: 68.50, merchant: Merchant.first) + review = Review.create(rating: 5, text_review: "This was better than my cast iron pan!", product_id: test.id) + test.reviews.must_include review + test.reviews[0].must_be_kind_of Review + test.must_respond_to :reviews + end + + it "has a list of orders it is in" do + order = orders(:pending_order) + product = products(:pointy_hat) + + product.must_respond_to :orders + product.orders << order + product.orders.count.must_equal 1 + end + + it "has categories" do + product = products(:pointy_hat) + + product.must_respond_to :categories + end + + end + + describe "#remove_one_from_stock" do + it "should change product.quantity_avail" do + product = products(:pointy_hat) + + proc { + product.remove_one_from_stock + }.must_change "product.quantity_avail", - 1 + end + + it "returns true if successful" do + product = products(:pointy_hat) + product.remove_one_from_stock.must_equal true + end + + it "should not change product quantity if product isn't available" do + product = products(:out_of_stock) + + proc { + product.remove_one_from_stock + }.wont_change "product.quantity_avail" + end + it "returns false if unsuccessful" do + product = products(:out_of_stock) + product.remove_one_from_stock.must_equal false + end + + end + describe "#add_one_to_stock" do + it "should change product.quantity_avail" do + product = products(:out_of_stock) + + proc { + product.add_one_to_stock + }.must_change "product.quantity_avail", 1 + end + it "should return true if successful" do + product = products(:out_of_stock) + + product.add_one_to_stock.must_equal true + end + end + describe "average_rating" do + it "can calculate an averate rating" do + test = Product.create(name: "Caldroun", quantity_avail: 5, price: 68.50, merchant: Merchant.first) + review = Review.create(rating: 1, text_review: "This was better than my cast iron pan!", product_id: test.id) + review2 = Review.create(rating: 3, text_review: "This was better than my cast iron pan!", product_id: test.id) + + test.average_rating.must_equal 2 + end + + it "Returns 'not yet rated' if no reviews" do + test = Product.create(name: "Caldroun", quantity_avail: 5, price: 68.50, merchant: Merchant.first) + + test.average_rating.must_equal "Not yet rated!" + end + + it "doesn't break if review is nil" do + test = Product.create(name: "Caldroun", quantity_avail: 5, price: 68.50, merchant: Merchant.first) + review = Review.create(rating: nil, text_review: "eh", product_id: test.id) + review = Review.create(rating: 3, text_review: "eh", product_id: test.id) + + test.average_rating.must_equal 3 + + end + end + +end diff --git a/test/models/review_test.rb b/test/models/review_test.rb new file mode 100644 index 0000000000..8de37130a0 --- /dev/null +++ b/test/models/review_test.rb @@ -0,0 +1,85 @@ +require "test_helper" +describe Review do + + describe "validations" do + it "requires a rating" do + test = Product.create(name: "Caldroun", quantity_avail: 5, price: 68.50, merchant: Merchant.first) + review = Review.new(text_review: "This was better than my cast iron pan!", product_id: test.id) + review.valid?.must_equal false + + review.rating = 5 + review.valid?.must_equal true + end + + it "requires a rating to be an integer" do + test = Product.create(name: "Caldroun", quantity_avail: 5, price: 68.50, merchant: Merchant.first) + review = Review.new(rating: "cats", text_review: "This was better than my cast iron pan!", product_id: test.id) + review.valid?.must_equal false + + + review = Review.new(rating: "cats", text_review: "This was better than my cast iron pan!", product_id: test.id) + review.rating = "Cats Rule!" + review.valid?.must_equal false + + review = Review.new(rating: "cats", text_review: "This was better than my cast iron pan!", product_id: test.id) + review.rating = 5 + review.valid?.must_equal true + end + + it "requires a rating to be an integer betwene 1 and 5" do + test = Product.create(name: "Caldroun", quantity_avail: 5, price: 68.50, merchant: Merchant.first) + review = Review.new(rating: 0, text_review: "This was better than my cast iron pan!", product_id: test.id) + review.valid?.must_equal false + + review.rating = 9 + review.valid?.must_equal false + + review.rating = 0 + review.valid?.must_equal false + + review.rating = -4 + review.valid?.must_equal false + end + + it "requires a product_id" do + test = Product.create(name: "Caldroun", quantity_avail: 5, price: 68.50, merchant: Merchant.first) + review = Review.new(text_review: "This was better than my cast iron pan!", rating: 4) + review.valid?.must_equal false + + review = Review.new(text_review: "This was better than my cast iron pan!", rating: 4, product_id: test.id) + review.valid?.must_equal true + end + + it "requires a valid product id" do + test = Product.create(name: "Caldroun", quantity_avail: 5, price: 68.50, merchant: Merchant.first) + review = Review.new(text_review: "This was better than my cast iron pan!", rating: 4, product_id: "CATSZZZ") + review.valid?.must_equal false + + review = Review.new(text_review: "This was better than my cast iron pan!", rating: 4, product_id: test.id) + review.valid?.must_equal true + end + end + + describe "relations" do + it "belongs to a product" do + test = Product.create(name: "Caldroun", quantity_avail: 5, price: 68.50, merchant: Merchant.first) + review = Review.create(text_review: "This was better than my cast iron pan!", rating: 4, product_id: test.id) + + test.reviews.must_include review + end + + it "is not associated with a product other than the one it belongs to" do + test = Product.create(name: "Caldroun", quantity_avail: 5, price: 68.50, merchant: Merchant.first) + review = Review.create(text_review: "This was better than my cast iron pan!", rating: 4, product_id: Product.first) + + test.reviews.wont_include review + end + + it "is is an empty collection if a product has no reviews" do + test = Product.create(name: "Caldroun", quantity_avail: 5, price: 68.50, merchant: Merchant.first) + + test.must_respond_to :reviews + test.reviews.count.must_equal 0 + end + end +end diff --git a/test/system/.keep b/test/system/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000000..b4f58c5b6d --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,52 @@ +ENV["RAILS_ENV"] = "test" +require File.expand_path("../../config/environment", __FILE__) +require "rails/test_help" +require "minitest/rails" +require "minitest/reporters" # for Colorized output + +# For colorful output! +Minitest::Reporters.use!( + Minitest::Reporters::SpecReporter.new, + ENV, + Minitest.backtrace_filter +) + +require 'simplecov' +SimpleCov.start + +# 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 + + def session_setup + post orders_path, params: { sig: orders } + end + + # Add more helper methods to be used by all tests here... + def setup + OmniAuth.config.test_mode = true + end + + def mock_auth_hash(merchant) + return { + provider: merchant.provider, + uid: merchant.uid, + info: { + email: merchant.email, + nickname: merchant.username + } + } + end + + def login(merchant) + OmniAuth.config.mock_auth[:github] = OmniAuth::AuthHash.new(mock_auth_hash(merchant)) + get auth_callback_path(:github) + end +end diff --git a/tmp/.keep b/tmp/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/.keep b/vendor/.keep new file mode 100644 index 0000000000..e69de29bb2