diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..18b43c9cd2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,27 @@
+# See https://help.github.com/articles/ignoring-files for more about ignoring files.
+#
+# If you find yourself ignoring temporary files generated by your text editor
+# or operating system, you probably want to add a global ignore instead:
+# git config --global core.excludesfile '~/.gitignore_global'
+
+# Ignore bundler config.
+/.bundle
+
+# Ignore all logfiles and tempfiles.
+/log/*
+/tmp/*
+!/log/.keep
+!/tmp/.keep
+
+# Ignore uploaded files in development
+/storage/*
+!/storage/.keep
+
+/node_modules
+/yarn-error.log
+
+/public/assets
+.byebug_history
+
+# Ignore master key for decrypting credentials and more.
+/config/master.key
diff --git a/.ruby-version b/.ruby-version
new file mode 100644
index 0000000000..25c81fe399
--- /dev/null
+++ b/.ruby-version
@@ -0,0 +1 @@
+ruby-2.5.1
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000000..6649301f60
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "workbench.colorCustomizations": {}
+}
\ No newline at end of file
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000000..80be142348
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,81 @@
+source 'https://rubygems.org'
+git_source(:github) { |repo| "https://github.com/#{repo}.git" }
+
+ruby '2.5.1'
+
+# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
+gem 'rails', '~> 5.2.3'
+# Use postgresql as the database for Active Record
+gem 'pg', '>= 0.18', '< 2.0'
+# Use Puma as the app server
+gem 'puma', '~> 3.11'
+# 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 'mini_racer', 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', '~> 4.0'
+# Use ActiveModel has_secure_password
+# gem 'bcrypt', '~> 3.1.7'
+
+# Use ActiveStorage variant
+# gem 'mini_magick', '~> 4.8'
+
+# Use Capistrano for deployment
+# gem 'capistrano-rails', group: :development
+
+# Reduces boot times through caching; required in config/boot.rb
+gem 'bootsnap', '>= 1.1.0', require: false
+
+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]
+end
+
+group :development do
+ # Access an interactive console on exception pages or by calling '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
+
+group :test do
+ # Adds support for Capybara system testing and selenium driver
+ gem 'capybara', '>= 2.15'
+ gem 'selenium-webdriver'
+ # Easy installation and use of chromedriver to run system tests with Chrome
+ gem 'chromedriver-helper'
+end
+
+# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
+gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
+
+gem 'jquery-rails'
+gem 'jquery-turbolinks'
+gem 'bootstrap', '~> 4.1.3'
+group :development, :test do
+ gem 'pry-rails'
+end
+
+group :development do
+ gem 'better_errors'
+ gem 'binding_of_caller'
+ gem 'guard'
+ gem 'guard-minitest'
+end
+
+group :test do
+ gem 'minitest-rails'
+ gem 'minitest-reporters'
+end
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000000..800e2e5b40
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,279 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ actioncable (5.2.3)
+ actionpack (= 5.2.3)
+ nio4r (~> 2.0)
+ websocket-driver (>= 0.6.1)
+ actionmailer (5.2.3)
+ actionpack (= 5.2.3)
+ actionview (= 5.2.3)
+ activejob (= 5.2.3)
+ mail (~> 2.5, >= 2.5.4)
+ rails-dom-testing (~> 2.0)
+ actionpack (5.2.3)
+ actionview (= 5.2.3)
+ activesupport (= 5.2.3)
+ rack (~> 2.0)
+ rack-test (>= 0.6.3)
+ rails-dom-testing (~> 2.0)
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
+ actionview (5.2.3)
+ activesupport (= 5.2.3)
+ builder (~> 3.1)
+ erubi (~> 1.4)
+ rails-dom-testing (~> 2.0)
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
+ activejob (5.2.3)
+ activesupport (= 5.2.3)
+ globalid (>= 0.3.6)
+ activemodel (5.2.3)
+ activesupport (= 5.2.3)
+ activerecord (5.2.3)
+ activemodel (= 5.2.3)
+ activesupport (= 5.2.3)
+ arel (>= 9.0)
+ activestorage (5.2.3)
+ actionpack (= 5.2.3)
+ activerecord (= 5.2.3)
+ marcel (~> 0.3.1)
+ activesupport (5.2.3)
+ concurrent-ruby (~> 1.0, >= 1.0.2)
+ i18n (>= 0.7, < 2)
+ minitest (~> 5.1)
+ tzinfo (~> 1.1)
+ addressable (2.6.0)
+ public_suffix (>= 2.0.2, < 4.0)
+ ansi (1.5.0)
+ archive-zip (0.12.0)
+ io-like (~> 0.3.0)
+ arel (9.0.0)
+ autoprefixer-rails (9.5.1)
+ execjs
+ better_errors (2.5.1)
+ coderay (>= 1.0.0)
+ erubi (>= 1.0.0)
+ rack (>= 0.9.0)
+ bindex (0.7.0)
+ binding_of_caller (0.8.0)
+ debug_inspector (>= 0.0.1)
+ bootsnap (1.4.3)
+ msgpack (~> 1.0)
+ bootstrap (4.1.3)
+ autoprefixer-rails (>= 6.0.3)
+ popper_js (>= 1.12.9, < 2)
+ sass (>= 3.5.2)
+ builder (3.2.3)
+ byebug (11.0.1)
+ capybara (3.18.0)
+ addressable
+ mini_mime (>= 0.1.3)
+ nokogiri (~> 1.8)
+ rack (>= 1.6.0)
+ rack-test (>= 0.6.3)
+ regexp_parser (~> 1.2)
+ xpath (~> 3.2)
+ childprocess (1.0.1)
+ rake (< 13.0)
+ chromedriver-helper (2.1.1)
+ archive-zip (~> 0.10)
+ nokogiri (~> 1.8)
+ coderay (1.1.2)
+ concurrent-ruby (1.1.5)
+ crass (1.0.4)
+ debug_inspector (0.0.3)
+ erubi (1.8.0)
+ execjs (2.7.0)
+ ffi (1.10.0)
+ formatador (0.2.5)
+ globalid (0.4.2)
+ activesupport (>= 4.2.0)
+ guard (2.15.0)
+ formatador (>= 0.2.4)
+ listen (>= 2.7, < 4.0)
+ lumberjack (>= 1.0.12, < 2.0)
+ nenv (~> 0.1)
+ notiffany (~> 0.0)
+ pry (>= 0.9.12)
+ shellany (~> 0.0)
+ thor (>= 0.18.1)
+ guard-compat (1.2.1)
+ guard-minitest (2.4.6)
+ guard-compat (~> 1.2)
+ minitest (>= 3.0)
+ i18n (1.6.0)
+ concurrent-ruby (~> 1.0)
+ io-like (0.3.0)
+ jbuilder (2.8.0)
+ activesupport (>= 4.2.0)
+ multi_json (>= 1.2)
+ jquery-rails (4.3.3)
+ rails-dom-testing (>= 1, < 3)
+ railties (>= 4.2.0)
+ thor (>= 0.14, < 2.0)
+ jquery-turbolinks (2.1.0)
+ railties (>= 3.1.0)
+ turbolinks
+ listen (3.1.5)
+ rb-fsevent (~> 0.9, >= 0.9.4)
+ rb-inotify (~> 0.9, >= 0.9.7)
+ ruby_dep (~> 1.2)
+ loofah (2.2.3)
+ crass (~> 1.0.2)
+ nokogiri (>= 1.5.9)
+ lumberjack (1.0.13)
+ mail (2.7.1)
+ mini_mime (>= 0.1.1)
+ marcel (0.3.3)
+ mimemagic (~> 0.3.2)
+ method_source (0.9.2)
+ mimemagic (0.3.3)
+ mini_mime (1.0.1)
+ mini_portile2 (2.4.0)
+ minitest (5.11.3)
+ minitest-rails (3.0.0)
+ minitest (~> 5.8)
+ railties (~> 5.0)
+ minitest-reporters (1.3.6)
+ ansi
+ builder
+ minitest (>= 5.0)
+ ruby-progressbar
+ msgpack (1.2.10)
+ multi_json (1.13.1)
+ nenv (0.3.0)
+ nio4r (2.3.1)
+ nokogiri (1.10.3)
+ mini_portile2 (~> 2.4.0)
+ notiffany (0.1.1)
+ nenv (~> 0.1)
+ shellany (~> 0.0)
+ pg (1.1.4)
+ popper_js (1.14.5)
+ pry (0.12.2)
+ coderay (~> 1.1.0)
+ method_source (~> 0.9.0)
+ pry-rails (0.3.9)
+ pry (>= 0.10.4)
+ public_suffix (3.0.3)
+ puma (3.12.1)
+ rack (2.0.7)
+ rack-test (1.1.0)
+ rack (>= 1.0, < 3)
+ rails (5.2.3)
+ actioncable (= 5.2.3)
+ actionmailer (= 5.2.3)
+ actionpack (= 5.2.3)
+ actionview (= 5.2.3)
+ activejob (= 5.2.3)
+ activemodel (= 5.2.3)
+ activerecord (= 5.2.3)
+ activestorage (= 5.2.3)
+ activesupport (= 5.2.3)
+ bundler (>= 1.3.0)
+ railties (= 5.2.3)
+ sprockets-rails (>= 2.0.0)
+ rails-dom-testing (2.0.3)
+ activesupport (>= 4.2.0)
+ nokogiri (>= 1.6)
+ rails-html-sanitizer (1.0.4)
+ loofah (~> 2.2, >= 2.2.2)
+ railties (5.2.3)
+ actionpack (= 5.2.3)
+ activesupport (= 5.2.3)
+ method_source
+ rake (>= 0.8.7)
+ thor (>= 0.19.0, < 2.0)
+ rake (12.3.2)
+ rb-fsevent (0.10.3)
+ rb-inotify (0.10.0)
+ ffi (~> 1.0)
+ regexp_parser (1.4.0)
+ ruby-progressbar (1.10.0)
+ ruby_dep (1.5.0)
+ rubyzip (1.2.2)
+ sass (3.7.4)
+ sass-listen (~> 4.0.0)
+ sass-listen (4.0.0)
+ rb-fsevent (~> 0.9, >= 0.9.4)
+ rb-inotify (~> 0.9, >= 0.9.7)
+ sass-rails (5.0.7)
+ railties (>= 4.0.0, < 6)
+ sass (~> 3.1)
+ sprockets (>= 2.8, < 4.0)
+ sprockets-rails (>= 2.0, < 4.0)
+ tilt (>= 1.1, < 3)
+ selenium-webdriver (3.141.5926)
+ childprocess (>= 0.5, < 2.0)
+ rubyzip (~> 1.2, >= 1.2.2)
+ shellany (0.0.1)
+ 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.2)
+ concurrent-ruby (~> 1.0)
+ rack (> 1, < 3)
+ sprockets-rails (3.2.1)
+ actionpack (>= 4.0)
+ activesupport (>= 4.0)
+ sprockets (>= 3.0.0)
+ thor (0.20.3)
+ thread_safe (0.3.6)
+ tilt (2.0.9)
+ turbolinks (5.2.0)
+ turbolinks-source (~> 5.2)
+ turbolinks-source (5.2.0)
+ tzinfo (1.2.5)
+ thread_safe (~> 0.1)
+ uglifier (4.1.20)
+ execjs (>= 0.3.0, < 3)
+ web-console (3.7.0)
+ actionview (>= 5.0)
+ activemodel (>= 5.0)
+ bindex (>= 0.4.0)
+ railties (>= 5.0)
+ websocket-driver (0.7.0)
+ websocket-extensions (>= 0.1.0)
+ websocket-extensions (0.1.3)
+ xpath (3.2.0)
+ nokogiri (~> 1.8)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ better_errors
+ binding_of_caller
+ bootsnap (>= 1.1.0)
+ bootstrap (~> 4.1.3)
+ byebug
+ capybara (>= 2.15)
+ chromedriver-helper
+ guard
+ guard-minitest
+ jbuilder (~> 2.5)
+ jquery-rails
+ jquery-turbolinks
+ listen (>= 3.0.5, < 3.2)
+ minitest-rails
+ minitest-reporters
+ pg (>= 0.18, < 2.0)
+ pry-rails
+ puma (~> 3.11)
+ rails (~> 5.2.3)
+ sass-rails (~> 5.0)
+ selenium-webdriver
+ spring
+ spring-watcher-listen (~> 2.0.0)
+ turbolinks (~> 5)
+ tzinfo-data
+ uglifier (>= 1.3.0)
+ web-console (>= 3.3.0)
+
+RUBY VERSION
+ ruby 2.5.1p57
+
+BUNDLED WITH
+ 2.0.1
diff --git a/Guardfile b/Guardfile
new file mode 100644
index 0000000000..e34f706f4a
--- /dev/null
+++ b/Guardfile
@@ -0,0 +1,9 @@
+guard :minitest, autorun: false, spring: true do
+ watch(%r{^app/(.+).rb$}) { |m| "test/#{m[1]}_test.rb" }
+ watch(%r{^app/controllers/application_controller.rb$}) { 'test/controllers' }
+ watch(%r{^app/controllers/(.+)_controller.rb$}) { |m| "test/integration/#{m[1]}_test.rb" }
+ watch(%r{^app/views/(.+)_mailer/.+}) { |m| "test/mailers/#{m[1]}_mailer_test.rb" }
+ watch(%r{^lib/(.+).rb$}) { |m| "test/lib/#{m[1]}_test.rb" }
+ watch(%r{^test/.+_test.rb$})
+ watch(%r{^test/test_helper.rb$}) { 'test' }
+end
diff --git a/README.md b/README.md
index 01d722e1fa..7db80e4ca1 100644
--- a/README.md
+++ b/README.md
@@ -1,141 +1,24 @@
-# Media Ranker
+# README
-## Introduction
+This README would normally document whatever steps are necessary to get the
+application up and running.
-In this project, you will build a webapp where users can vote for their favorite pieces of media.
+Things you may want to cover:
-In contrast to previous projects, instead of implementing a pre-defined spec you will be imitating an existing site: http://media-ranker-2-0.herokuapp.com. Your job is to match the functionality and styling of this site as closely as possible.
+* Ruby version
-This is an individual, [stage 2](https://github.com/Ada-Developers-Academy/pedagogy/blob/master/rule-of-three.md) project, due before class Monday April 29.
+* System dependencies
-## Learning Goals
+* Configuration
-The purpose of this assignment is to reinforce the following concepts:
+* Database creation
-- Previous Rails learning, including MVC, RESTful routing, and the request cycle
-- Testing Rails applications
-- Building complex model logic
-- Using `session` and `flash` to track data between requests
-- DRYing up Rails code
+* Database initialization
-## Before You Begin
+* How to run the test suite
-### Provided Files
+* Services (job queues, cache servers, search engines, etc.)
-- `db/media_seeds.csv`: Some starter media to work with
-- `app/assets/images/owl.jpg`: The owl picture from the site
+* Deployment instructions
-### Regarding the Word "Media"
-
-The Rails inflector considers "media" to be the plural of "medium", which is not really what we mean here. You may want to choose a different word to represent "a book, movie or album" internally. The instructor-proved example site uses the word "work".
-
-## Project Requirements
-
-### Core Requirements
-
-Regardless of how you choose to implement this project or how much of it gets done, you should exhibit
-
-- Squeaky-clean **git hygiene**, including
- - A fresh branch for each new feature
- - Regular commits
- - Descriptive commit messages
-- Fanatical devotion to **test-driven development**
- - Pseudocode first, then write the tests, then write code to make them pass
-- Steadfast adherence to **agile development practices**
- - User stories should be listed and prioritized using a Trello board
- - The finished application should be deployed to Heroku (deploy early, deploy often)
-- Unrelenting use of **semantic HTML**
-
-### Baseline
-
-We will begin with some in-class work, exploring the site and pondering implementation details. Before you start writing _any_ code, you should:
-
-- Explore the existing Media Ranker site to become familiar with the necessary functionality
-- Create a Trello board to manage user stories
-- Create an ERD for the models
-
-Then, once you have a solid plan for how to structure your project:
-
-- Fork and clone the repo
-- Use `rails new .` to generate a new Rails project in the cloned directory
- - Verify that the changes we've made to Rails' defaults (postgres as the DB, spec-style testing) have been applied
-- `git add .` and `git commit -m "Initial Rails setup"`
-
-### Wave 1
-
-In this wave, you should build some functionality, and then build the tests for that functionality. We recommend doing the read and create operations first, then writing tests, then completing the update and delete operations.
-
-Mimic the site's basic functionality around Media, without worrying (yet) about Users or Votes:
-- Build a main page, with a list of the media for each category, as well as a spotlight section for the top media overall.
- - Since we don't have votes yet, for both the spotlight and top-10 sections you should select works at random (i.e. using `.sample`)
-- Build an index page with a list of all works for each category
-- Allow users to add new works
-- Build a details page for each piece of media
-- Allow users to edit and delete works
-
-#### Organization
-
-Think about what functionality should live in the model. Given that the way you select the spotlight and top-10 are going to change in a future wave, how can you isolate this business logic to make it easy to change?
-
-#### Testing
-
-**Before** moving on to wave 2, your project should contain the following tests
-
-**Model Testing**
-- All validations and should be tested
-- All custom methods should be tested
- - For top-10 or spotlight, what if there are less than 10 works? What if there are no works?
-
-**Controller Testing**
-- Tests for standard CRUD operations on works
-- Does the main page load if there are no works?
-
-### Wave 2
-
-Mimic the site's functionality around Users and Voting:
-- Allow users to "log in" to the site, and use the `session` to keep track of which user is currently logged in for a given browser
-- Allow users to vote for media, and sort media by vote count whenever a list of media is displayed
-- Don't allow a user to vote for the same media more than once
-- Change the media spotlight and top-10 to respect vote count
-
-#### Testing
-
-**Before** moving on to wave 3, your project should contain the following tests
-
-**Model Testing**
-- All validations for new models should be tested
-- All relations between models should be tested
-- Your tests for custom model methods should be updated to reflect the presence of votes
- - How do top-10 and spotlight handle works with no votes? Ties in the number of votes?
-
-**Controller Testing**
-- Tests for all individual actions
-- Authentication tests combining multiple actions
- - A guest user _cannot_ vote if they have not logged in
- - A logged-in user _can_ vote for a work they haven't already voted for
- - A logged-in user _cannot_ vote for a work they have previously voted for
-
-Focus on testing voting logic since this is the most complex part of Wave 2.
-
-#### A note on logging in
-
-Passwords and security are tricky! We'll talk about that sort of thing a little in the coming weeks, but for now you don't need to provide any sort of security. The user gives you a username, and your site should just trust them.
-
-### Wave 3
-- Add a list of voting users to the details page for each media
-- Add a page for each user, as well as a page showing a summary of all users
-
-### Optional Enhancement Ideas
-
-Use Bootstrap and CSS to style the site to match the example. The layout as well as the look and feel should match as close as possible.
-
-Once your test coverage is comprehensive, your HTML is semantic, your user stories have all been moved to the `Done` column and your application has been deployed to Heroku, you may consider the following enhancements.
-
-1. DRY up your code as much as you can! Techniques worth investigating:
- - Helper methods
- - Controller filters
-1. Build category-specific pages for `index` and `new` (e.g. `/books` or `/movies/new`). These should be as DRY as possible. You might be interested in investigating _polymorphic routes_.
-1. Add a [recommendation system](https://www.toptal.com/algorithms/predicting-likes-inside-a-simple-recommendation-engine) that suggests media to a user based on what they have previously voted for.
-
-## What we're looking for
-You can find what instructors will be looking for in the [feedback](feedback.md) markdown document.
+* ...
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..b0ef35b723
--- /dev/null
+++ b/app/assets/javascripts/application.js
@@ -0,0 +1,19 @@
+// This is a manifest file that'll be compiled into application.js, which will include all the files
+// listed below.
+//
+// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, 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 jquery3
+ //= require popper
+ //= require bootstrap-sprockets
+
+//
+//= require rails-ujs
+//= require activestorage
+//= require turbolinks
+//= require_tree .
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/channels/.keep b/app/assets/javascripts/channels/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/app/assets/javascripts/landing.js b/app/assets/javascripts/landing.js
new file mode 100644
index 0000000000..dee720facd
--- /dev/null
+++ b/app/assets/javascripts/landing.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/javascripts/users.js b/app/assets/javascripts/users.js
new file mode 100644
index 0000000000..dee720facd
--- /dev/null
+++ b/app/assets/javascripts/users.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/works.js b/app/assets/javascripts/works.js
new file mode 100644
index 0000000000..dee720facd
--- /dev/null
+++ b/app/assets/javascripts/works.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/application.scss b/app/assets/stylesheets/application.scss
new file mode 100644
index 0000000000..2d5b5c2883
--- /dev/null
+++ b/app/assets/stylesheets/application.scss
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ *
+ */
+/* Custom bootstrap variables must be set or imported *before* bootstrap. */
+@import "bootstrap";
+
+body {
+ font-family: 'Gudea', sans-serif;
+}
+
+header {
+ background-color: #B2DFDB;
+ padding-top: 3rem;
+ padding-left: 1rem;
+ padding-right: 1rem;
+}
+
+.title {
+ border-right: solid;
+ border-width: .1rem;
+ margin: 1rem 1rem;
+ padding: 0 1.5rem;
+}
+
+h1 {
+ text-align: center;
+ color: white;
+ font-weight: bold;
+}
+
+h1 a:link, h1 a:visited {
+ color: #FF5722;
+ text-decoration: none;
+}
+
+nav {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ padding-top: 3rem;
+ padding-bottom: .5rem;
+}
+
+.nav-link {
+ color: #00796B;
+ text-decoration: none;
+}
+
+.nav-link:hover {
+ color: #00796B;
+}
+
+.btn-primary {
+ background-color: #26A69A;
+ border-color: #26A69A;
+ color: white;
+}
+
+.user {
+ margin-right: 1.5rem;
+}
+
+.btn-primary:hover {
+ background-color: #00796B;
+}
+
+.btn-secondary:hover {
+ background-color: #00796B;
+}
+
+.btn-danger:hover {
+ background-color: #00796B;
+}
+
+h2, h3 {
+ color: #26A69A;
+ font-weight: bold;
+}
+
+h4 {
+ font-weight: bold;
+}
+
+a {
+ color: #26A69A;
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: none;
+ color: #00796B;
+}
+
+ul {
+ list-style: none;
+}
+
+.flash {
+ padding-top: 1rem 1rem;
+}
+
+.alert-warning {
+ padding: 1rem 1rem;
+}
+
+.alert-success {
+ padding: 1rem 1rem;
+}
+
+main {
+ padding: 1rem 2rem;
+}
+
+.spotlight {
+ padding: 0 2rem 2rem 2rem;
+ border-bottom: 1px solid;
+ border-bottom-color: lightgray;
+ margin-bottom: 2rem;
+}
+
+.spotlight-header {
+ color: #424242;
+}
+
+.spotlight-title {
+ border-bottom: solid;
+}
+
+.top-ten-container {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+ grid-column-gap: 2em;
+}
+
+.top-ten-header {
+ color: #26A69A;
+ border-bottom: 2px solid;
+ border-bottom-color: #B2DFDB;
+}
+
+.list-group-item {
+ border: none;
+}
+
+.top-ten-title {
+ font-weight: bold;
+}
+
+.top-ten-creator {
+ color: gray;
+}
+
+.media-vote {
+ margin-top: 2rem;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/landing.scss b/app/assets/stylesheets/landing.scss
new file mode 100644
index 0000000000..869e6f42ee
--- /dev/null
+++ b/app/assets/stylesheets/landing.scss
@@ -0,0 +1,6 @@
+// Place all the styles related to the landing controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
+.list-group-item {
+ border: none;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/sessions.scss b/app/assets/stylesheets/sessions.scss
new file mode 100644
index 0000000000..ccb1ed25b2
--- /dev/null
+++ b/app/assets/stylesheets/sessions.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the Sessions controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
diff --git a/app/assets/stylesheets/users.scss b/app/assets/stylesheets/users.scss
new file mode 100644
index 0000000000..31a2eacb84
--- /dev/null
+++ b/app/assets/stylesheets/users.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the Users 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/works.scss b/app/assets/stylesheets/works.scss
new file mode 100644
index 0000000000..75bb30b8d6
--- /dev/null
+++ b/app/assets/stylesheets/works.scss
@@ -0,0 +1,7 @@
+// Place all the styles related to the Works controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
+a {
+ color: #26A69A;
+ font-weight: bold;
+}
\ No newline at end of file
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..2b98619f10
--- /dev/null
+++ b/app/controllers/application_controller.rb
@@ -0,0 +1,11 @@
+class ApplicationController < ActionController::Base
+ before_action :find_user
+
+ private
+
+ def find_user
+ if session[:user_id]
+ @super_user = User.find_by(id: session[:user_id])
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/app/controllers/landing_controller.rb b/app/controllers/landing_controller.rb
new file mode 100644
index 0000000000..852af5efde
--- /dev/null
+++ b/app/controllers/landing_controller.rb
@@ -0,0 +1,9 @@
+
+class LandingController < ApplicationController
+ def index
+ @top_media = Work.top_media
+ @top_movies = Work.top_ten("movie")
+ @top_books = Work.top_ten("book")
+ @top_albums = Work.top_ten("album")
+ end
+end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
new file mode 100644
index 0000000000..bb7898b289
--- /dev/null
+++ b/app/controllers/sessions_controller.rb
@@ -0,0 +1,24 @@
+class SessionsController < ApplicationController
+ def login
+ username = params[:username]
+ if !username.nil? && user = User.find_by(username: username)
+ flash[:success] = "Welcome back, #{user.username}!"
+ else
+ user = User.new(username: username)
+ if user.save
+ session[:user_id] = user.id
+ flash[:success] = "New user created: #{user.username} with ID #{user.id}"
+ else
+ flash.now[:failure] = "Login failed"
+ render :new
+ end
+ end
+ redirect_to root_path
+ end
+
+ def logout
+ session[:user_id] = nil
+ flash[:success] = "You have logged out."
+ redirect_to root_path
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
new file mode 100644
index 0000000000..415c4031bd
--- /dev/null
+++ b/app/controllers/users_controller.rb
@@ -0,0 +1,10 @@
+class UsersController < ApplicationController
+ def index
+ @users = User.all
+ end
+
+ def show
+ @user = User.find_by(id: params[:id])
+ render :not_found unless @user
+ end
+end
diff --git a/app/controllers/works_controller.rb b/app/controllers/works_controller.rb
new file mode 100644
index 0000000000..f5543e1f06
--- /dev/null
+++ b/app/controllers/works_controller.rb
@@ -0,0 +1,79 @@
+class WorksController < ApplicationController
+ before_action :find_work, only: [:show, :edit, :update, :destroy, :upvote]
+
+ def index
+ @movies = Work.category_list("movie")
+ @books = Work.category_list("book")
+ @albums = Work.category_list("album")
+ end
+
+ def show
+ if @work.nil?
+ render :not_found, status: :not_found
+ end
+ end
+
+ def new
+ @work = Work.new
+ end
+
+ def create
+ @work = Work.new(work_params)
+ if @work.save
+ flash[:success] = "Successfully created #{@work.category} #{@work.id}"
+ redirect_to work_path(@work)
+ else
+ flash.now[:warning] = "A problem occurred: Could not create #{@work.category}"
+ render :new
+ end
+ end
+
+ def edit
+ end
+
+ def update
+ if @work.update(work_params)
+ flash[:success] = "Successfully updated #{@work.category} #{@work.id}"
+ redirect_to work_path(@work.id)
+ else
+ flash.now[:warning] = "Could not update #{@work.category}"
+ render :edit
+ end
+ end
+
+ def destroy
+ unless @work.nil?
+ @work.votes.destroy_all
+ end
+
+ @deleted_work = @work.destroy
+ flash[:success] = "Successfully destroyed #{@deleted_work.category} #{@deleted_work.id}"
+ redirect_to root_path
+ end
+
+ def upvote
+ if @super_user.nil?
+ flash[:warning] = "Please log in so your vote can be counted."
+ redirect_to login_path
+ else
+ if @super_user.has_voted?(@work.id)
+ flash[:warning] = "Sorry, you can't vote twice on the same work."
+ redirect_back fallback_location: works_path
+ else
+ Vote.create(user_id: @super_user.id, work_id: @work.id)
+ flash[:success] = "Your vote has been counted!"
+ redirect_back fallback_location: works_path
+ end
+ end
+ end
+
+ private
+
+ def work_params
+ params.require(:work).permit(:category, :title, :creator, :publication_year, :description)
+ end
+
+ def find_work
+ @work = Work.find_by(id: params[:id])
+ end
+end
\ No newline at end of file
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/landing_helper.rb b/app/helpers/landing_helper.rb
new file mode 100644
index 0000000000..6aa3ee9247
--- /dev/null
+++ b/app/helpers/landing_helper.rb
@@ -0,0 +1,2 @@
+module LandingHelper
+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/helpers/users_helper.rb b/app/helpers/users_helper.rb
new file mode 100644
index 0000000000..2310a240d7
--- /dev/null
+++ b/app/helpers/users_helper.rb
@@ -0,0 +1,2 @@
+module UsersHelper
+end
diff --git a/app/helpers/works_helper.rb b/app/helpers/works_helper.rb
new file mode 100644
index 0000000000..ccb78c2b73
--- /dev/null
+++ b/app/helpers/works_helper.rb
@@ -0,0 +1,2 @@
+module WorksHelper
+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/concerns/.keep b/app/models/concerns/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/app/models/user.rb b/app/models/user.rb
new file mode 100644
index 0000000000..e6797c8f7d
--- /dev/null
+++ b/app/models/user.rb
@@ -0,0 +1,10 @@
+class User < ApplicationRecord
+ has_many :votes
+
+ def has_voted?(work_id)
+ votes = self.votes
+ return votes.find_by(work_id: work_id)
+ end
+
+ validates :username, presence: true, uniqueness: true
+end
\ No newline at end of file
diff --git a/app/models/vote.rb b/app/models/vote.rb
new file mode 100644
index 0000000000..959bc77430
--- /dev/null
+++ b/app/models/vote.rb
@@ -0,0 +1,8 @@
+class Vote < ApplicationRecord
+ belongs_to :work, counter_cache: :vote_count
+ belongs_to :user
+
+ validates :user_id, presence: true
+ validates :work_id, presence: true
+
+end
\ No newline at end of file
diff --git a/app/models/work.rb b/app/models/work.rb
new file mode 100644
index 0000000000..b25377b99d
--- /dev/null
+++ b/app/models/work.rb
@@ -0,0 +1,29 @@
+class Work < ApplicationRecord
+ has_many :votes
+
+ validates :title, presence: true
+
+ def self.top_media
+ if Work.all == nil || Work.all == []
+ return nil
+ end
+
+ return Work.all.max_by { |work| work.vote_count }
+ end
+
+ def self.category_list(category)
+ category_list = Work.select { |work| work.category == category }
+ return category_list.sort_by { |work| work.vote_count }.reverse!
+ end
+
+ def self.top_ten(category)
+ works = Work.category_list(category)
+
+ return works[0..9]
+ end
+
+ def vote_count
+ return self.votes.length
+ end
+
+end
\ No newline at end of file
diff --git a/app/views/landing/_category.html.erb b/app/views/landing/_category.html.erb
new file mode 100644
index 0000000000..cf1163c094
--- /dev/null
+++ b/app/views/landing/_category.html.erb
@@ -0,0 +1,11 @@
+
+
There is no password field. Be nice. Friends do not impersonate friends.
+
diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb
new file mode 100644
index 0000000000..b62cceb497
--- /dev/null
+++ b/app/views/users/index.html.erb
@@ -0,0 +1,22 @@
+
List of Users
+
+
+
+
+
Username
+
Votes
+
Joined
+
+
+
+
+ <% @users.each do |user| %>
+
<%= link_to user.username, user_path(user) %>
+
<%= user.votes.length %>
+
<%= user.created_at.strftime("%B %d, %Y") %>
+
+ <% end %>
+
+
+
+<%= link_to "Back to Media List", root_path, class: "btn btn-secondary" %>
\ No newline at end of file
diff --git a/app/views/users/not_found.html.erb b/app/views/users/not_found.html.erb
new file mode 100644
index 0000000000..99a8d8c235
--- /dev/null
+++ b/app/views/users/not_found.html.erb
@@ -0,0 +1 @@
+404 nope :(
\ No newline at end of file
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb
new file mode 100644
index 0000000000..d4defe358c
--- /dev/null
+++ b/app/views/users/show.html.erb
@@ -0,0 +1,30 @@
+
User Summary: <%= @user.username %>
+
Joined site <%= @user.created_at.strftime("%B %d, %Y") %>
+
+<%= link_to "See all Users", users_path, class: "btn btn-secondary" %>
+<%= link_to "Back to Media List", root_path, class: "btn btn-primary" %>
\ No newline at end of file
diff --git a/app/views/works/_category.html.erb b/app/views/works/_category.html.erb
new file mode 100644
index 0000000000..5ac93d795d
--- /dev/null
+++ b/app/views/works/_category.html.erb
@@ -0,0 +1,23 @@
+
\ No newline at end of file
diff --git a/app/views/works/_form.html.erb b/app/views/works/_form.html.erb
new file mode 100644
index 0000000000..0ee6940a99
--- /dev/null
+++ b/app/views/works/_form.html.erb
@@ -0,0 +1,25 @@
+<%= form_with model: @work do |f| %>
+
+<% end %>
\ No newline at end of file
diff --git a/app/views/works/edit.html.erb b/app/views/works/edit.html.erb
new file mode 100644
index 0000000000..be1722995f
--- /dev/null
+++ b/app/views/works/edit.html.erb
@@ -0,0 +1,2 @@
+
Edit This Album
+<%= render partial: "form", locals: { } %>
\ No newline at end of file
diff --git a/app/views/works/index.html.erb b/app/views/works/index.html.erb
new file mode 100644
index 0000000000..a1dc58c3b3
--- /dev/null
+++ b/app/views/works/index.html.erb
@@ -0,0 +1,8 @@
+
List of Works
+
+ <%= render partial: "category", locals: { category_name: "Albums", category: @albums } %>
+ <%= render partial: "category", locals: { category_name: "Books", category: @books } %>
+ <%= render partial: "category", locals: { category_name: "Movies", category: @movies } %>
+
+<%= link_to "View top media", root_path, class: "btn btn-secondary" %>
+<%= link_to "Add a new work", new_work_path, class: "btn btn-primary" %>
\ No newline at end of file
diff --git a/app/views/works/new.html.erb b/app/views/works/new.html.erb
new file mode 100644
index 0000000000..7359f3d1e8
--- /dev/null
+++ b/app/views/works/new.html.erb
@@ -0,0 +1,2 @@
+
Add a new work
+<%= render partial: "form", locals: { } %>
\ No newline at end of file
diff --git a/app/views/works/not_found.html.erb b/app/views/works/not_found.html.erb
new file mode 100644
index 0000000000..99a8d8c235
--- /dev/null
+++ b/app/views/works/not_found.html.erb
@@ -0,0 +1 @@
+404 nope :(
\ No newline at end of file
diff --git a/app/views/works/show.html.erb b/app/views/works/show.html.erb
new file mode 100644
index 0000000000..46bad3b05e
--- /dev/null
+++ b/app/views/works/show.html.erb
@@ -0,0 +1,33 @@
+
+
+
\ No newline at end of file
diff --git a/bin/bundle b/bin/bundle
new file mode 100755
index 0000000000..f19acf5b5c
--- /dev/null
+++ b/bin/bundle
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
+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..94fd4d7977
--- /dev/null
+++ b/bin/setup
@@ -0,0 +1,36 @@
+#!/usr/bin/env ruby
+require 'fileutils'
+include FileUtils
+
+# path to your application root.
+APP_ROOT = File.expand_path('..', __dir__)
+
+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..58bfaed518
--- /dev/null
+++ b/bin/update
@@ -0,0 +1,31 @@
+#!/usr/bin/env ruby
+require 'fileutils'
+include FileUtils
+
+# path to your application root.
+APP_ROOT = File.expand_path('..', __dir__)
+
+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')
+
+ # Install JavaScript dependencies if using Yarn
+ # system('bin/yarn')
+
+ puts "\n== Updating database =="
+ system! 'bin/rails db:migrate'
+
+ puts "\n== Removing old logs and tempfiles =="
+ system! 'bin/rails log:clear tmp:clear'
+
+ puts "\n== Restarting application server =="
+ system! 'bin/rails restart'
+end
diff --git a/bin/yarn b/bin/yarn
new file mode 100755
index 0000000000..460dd565b4
--- /dev/null
+++ b/bin/yarn
@@ -0,0 +1,11 @@
+#!/usr/bin/env ruby
+APP_ROOT = File.expand_path('..', __dir__)
+Dir.chdir(APP_ROOT) do
+ begin
+ exec "yarnpkg", *ARGV
+ rescue Errno::ENOENT
+ $stderr.puts "Yarn executable was not detected in the system."
+ $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
+ exit 1
+ end
+end
diff --git a/config.ru b/config.ru
new file mode 100644
index 0000000000..f7ba0b527b
--- /dev/null
+++ b/config.ru
@@ -0,0 +1,5 @@
+# This file is used by Rack-based servers to start the application.
+
+require_relative 'config/environment'
+
+run Rails.application
diff --git a/config/application.rb b/config/application.rb
new file mode 100644
index 0000000000..08db79cb25
--- /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 MediaRanker
+ 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.2
+
+ # Settings in config/environments/* take precedence over those specified here.
+ # Application configuration can go into files in config/initializers
+ # -- all .rb files in that directory are automatically loaded after loading
+ # the framework and any gems in your application.
+ end
+end
diff --git a/config/boot.rb b/config/boot.rb
new file mode 100644
index 0000000000..b9e460cef3
--- /dev/null
+++ b/config/boot.rb
@@ -0,0 +1,4 @@
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
+
+require 'bundler/setup' # Set up gems listed in the Gemfile.
+require 'bootsnap/setup' # Speed up boot time by caching expensive operations.
diff --git a/config/cable.yml b/config/cable.yml
new file mode 100644
index 0000000000..0b286f676e
--- /dev/null
+++ b/config/cable.yml
@@ -0,0 +1,10 @@
+development:
+ adapter: async
+
+test:
+ adapter: async
+
+production:
+ adapter: redis
+ url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
+ channel_prefix: MediaRanker_production
diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc
new file mode 100644
index 0000000000..8aa3279de7
--- /dev/null
+++ b/config/credentials.yml.enc
@@ -0,0 +1 @@
+e2w8vTCEBN2kGM88nZ3I+oAgdtdjzo8ogLDBUr7QEE8ww8bHiBAetaPj4ai3aenvtAdz5cYGVrykip4AzPi0yb242G1Kay7cyLfLrJql4hn/KAUO7LLZbB5LiAO7a7N0+v4aCq8qwroP5DtjW62VFTh393/E5p3HYkjYWvtT0SA309a7d6W/bqqO/Z0Idv0j04hqE4DNuH7VBVrT80eDpXrXV4XAqH9LpzzTflFeuStzJAHrrPFDoHbCNz2Eamzkj00p/2fzaEPO5R6VMp+k1JOT1hSuRNkwd+VeaWdsXJWLjDhyXCvEjlAqPvjHJCejlElJEoB3by41etWZZb45G5CvGjzOcTR1doF6aRma/Yio6Tp9WhW68yST4ku/OTf0e1zOESN500iWTQzfngIJ2jCDrc3/SCKnt59W--+GWV/9SdD0B+VVQI--lBzUnw4pT3rrajo9HRHSIA==
\ No newline at end of file
diff --git a/config/database.yml b/config/database.yml
new file mode 100644
index 0000000000..0bd2511123
--- /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: MediaRanker_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: MediaRanker
+
+ # 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: MediaRanker_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: MediaRanker_production
+ username: MediaRanker
+ password: <%= ENV['MEDIARANKER_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..1311e3e4ef
--- /dev/null
+++ b/config/environments/development.rb
@@ -0,0 +1,61 @@
+Rails.application.configure do
+ # Settings specified here will take precedence over those in config/application.rb.
+
+ # In the development environment your application's code is reloaded on
+ # every request. This slows down response time but is perfect for development
+ # since you don't have to restart the web server when you make code changes.
+ config.cache_classes = false
+
+ # Do not eager load code on boot.
+ config.eager_load = false
+
+ # Show full error reports.
+ config.consider_all_requests_local = true
+
+ # Enable/disable caching. By default caching is disabled.
+ # Run rails dev:cache to toggle caching.
+ 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.to_i}"
+ }
+ else
+ config.action_controller.perform_caching = false
+
+ config.cache_store = :null_store
+ end
+
+ # Store uploaded files on the local file system (see config/storage.yml for options)
+ config.active_storage.service = :local
+
+ # 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
+
+ # Highlight code that triggered database queries in logs.
+ config.active_record.verbose_query_logs = true
+
+ # 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..bd39d9d752
--- /dev/null
+++ b/config/environments/production.rb
@@ -0,0 +1,94 @@
+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
+
+ # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
+ # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
+ # config.require_master_key = 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
+
+ # Store uploaded files on the local file system (see config/storage.yml for options)
+ config.active_storage.service = :local
+
+ # 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 = "MediaRanker_#{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..0a38fd3ce9
--- /dev/null
+++ b/config/environments/test.rb
@@ -0,0 +1,46 @@
+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.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
+
+ # Store uploaded files on the local file system in a temporary directory
+ config.active_storage.service = :test
+
+ 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/action_view.rb b/config/initializers/action_view.rb
new file mode 100644
index 0000000000..142d382f87
--- /dev/null
+++ b/config/initializers/action_view.rb
@@ -0,0 +1 @@
+Rails.application.config.action_view.form_with_generates_remote_forms = false
diff --git a/config/initializers/application_controller_renderer.rb b/config/initializers/application_controller_renderer.rb
new file mode 100644
index 0000000000..89d2efab2b
--- /dev/null
+++ b/config/initializers/application_controller_renderer.rb
@@ -0,0 +1,8 @@
+# Be sure to restart your server when you modify this file.
+
+# ActiveSupport::Reloader.to_prepare do
+# ApplicationController.renderer.defaults.merge!(
+# http_host: 'example.org',
+# https: false
+# )
+# end
diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb
new file mode 100644
index 0000000000..4b828e80cb
--- /dev/null
+++ b/config/initializers/assets.rb
@@ -0,0 +1,14 @@
+# Be sure to restart your server when you modify this file.
+
+# Version of your assets, change this if you want to expire all your assets.
+Rails.application.config.assets.version = '1.0'
+
+# Add additional assets to the asset load path.
+# Rails.application.config.assets.paths << Emoji.images_path
+# Add Yarn node_modules folder to the asset load path.
+Rails.application.config.assets.paths << Rails.root.join('node_modules')
+
+# Precompile additional assets.
+# application.js, application.css, and all non-JS/CSS in the app/assets
+# folder are already added.
+# Rails.application.config.assets.precompile += %w( admin.js admin.css )
diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb
new file mode 100644
index 0000000000..59385cdf37
--- /dev/null
+++ b/config/initializers/backtrace_silencers.rb
@@ -0,0 +1,7 @@
+# Be sure to restart your server when you modify this file.
+
+# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
+# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
+
+# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
+# Rails.backtrace_cleaner.remove_silencers!
diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb
new file mode 100644
index 0000000000..d3bcaa5ec8
--- /dev/null
+++ b/config/initializers/content_security_policy.rb
@@ -0,0 +1,25 @@
+# Be sure to restart your server when you modify this file.
+
+# Define an application-wide content security policy
+# For further information see the following documentation
+# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
+
+# Rails.application.config.content_security_policy do |policy|
+# policy.default_src :self, :https
+# policy.font_src :self, :https, :data
+# policy.img_src :self, :https, :data
+# policy.object_src :none
+# policy.script_src :self, :https
+# policy.style_src :self, :https
+
+# # Specify URI for violation reports
+# # policy.report_uri "/csp-violation-report-endpoint"
+# end
+
+# If you are using UJS then enable automatic nonce generation
+# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
+
+# Report CSP violations to a specified URI
+# For further information see the following documentation:
+# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
+# Rails.application.config.content_security_policy_report_only = true
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/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..a5eccf816b
--- /dev/null
+++ b/config/puma.rb
@@ -0,0 +1,34 @@
+# 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.
+#
+# preload_app!
+
+# 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..1b24069803
--- /dev/null
+++ b/config/routes.rb
@@ -0,0 +1,13 @@
+Rails.application.routes.draw do
+ root 'landing#index'
+
+ get '/login', to: 'sessions#new', as: 'login'
+ post '/login', to: 'sessions#login'
+ post '/logout', to: 'sessions#logout', as: 'logout'
+
+ post 'works/:id/upvote', to: 'works#upvote', as: 'upvote'
+ resources :works
+
+ resources :users, only: [:index, :show]
+ # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
+end
\ No newline at end of file
diff --git a/config/spring.rb b/config/spring.rb
new file mode 100644
index 0000000000..9fa7863f99
--- /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/config/storage.yml b/config/storage.yml
new file mode 100644
index 0000000000..d32f76e8fb
--- /dev/null
+++ b/config/storage.yml
@@ -0,0 +1,34 @@
+test:
+ service: Disk
+ root: <%= Rails.root.join("tmp/storage") %>
+
+local:
+ service: Disk
+ root: <%= Rails.root.join("storage") %>
+
+# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
+# amazon:
+# service: S3
+# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
+# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
+# region: us-east-1
+# bucket: your_own_bucket
+
+# Remember not to checkin your GCS keyfile to a repository
+# google:
+# service: GCS
+# project: your_project
+# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
+# bucket: your_own_bucket
+
+# Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
+# microsoft:
+# service: AzureStorage
+# storage_account_name: your_account_name
+# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
+# container: your_container_name
+
+# mirror:
+# service: Mirror
+# primary: local
+# mirrors: [ amazon, google, microsoft ]
diff --git a/db/generate_seeds.rb b/db/generate_seeds.rb
index 19fca77936..9c40b8003f 100644
--- a/db/generate_seeds.rb
+++ b/db/generate_seeds.rb
@@ -12,12 +12,12 @@
CSV.open("db/media_seeds.csv", "w", :write_headers => true,
:headers => ["category", "title", "creator", "publication_year", "description"]) do |csv|
- 25.times do
- category = %w(album book).sample
- title = Faker::Coffee.blend_name
- creator = Faker::Name.name
+ 100.times do
+ category = %w(album movie book).sample
+ title = Faker::Hacker.adjective.capitalize + " " + Faker::ElectricalComponents.electromechanical
+ creator = Faker::Superhero.name
publication_year = rand(Date.today.year - 100..Date.today.year)
- description = Faker::Lorem.sentence
+ description = Faker::Company.catch_phrase + Faker::Company.bs
csv << [category, title, creator, publication_year, description]
end
diff --git a/db/media_seeds.csv b/db/media_seeds.csv
index 5f5b252a25..c2fdac5c76 100644
--- a/db/media_seeds.csv
+++ b/db/media_seeds.csv
@@ -1,25 +1,101 @@
category,title,creator,publication_year,description
-album,Blue Breaker,Dr. Sarai Langosh,1949,Et et expedita non aut quo.
-book,Joe Treat,Blaise Lesch,1968,Voluptatem adipisci qui velit.
-album,Kreb-Full-o Been,Ms. Trevion Buckridge,2016,Vero consectetur delectus consequatur id aut accusantium unde excepturi.
-album,Wake-up Pie,Timmy Streich I,1919,Voluptatem consequatur qui consectetur nisi officiis culpa.
-album,Major Cup,Jayde Bartoletti,1944,Quis recusandae cum est facere consequatur minima magni et.
-book,Summer Select,Ms. Gwendolyn Ortiz,1946,Et molestiae eos nam odit aut sed.
-album,Holiday Choice,Alexandria Lehner,1940,Excepturi voluptas ut voluptatum.
-book,Postmodern Blend,Meredith Brekke,1970,Dolorem fugit accusantium qui.
-book,Green Forrester,Raquel Hirthe,1933,Omnis qui quia odio.
-album,Winter Mug,Tia Weissnat II,1990,Laboriosam autem iusto quae sed voluptate et.
-book,Red Pie,Davon Kub,1961,Id dolorem qui laborum quia.
-album,Major Equinox,Queen Satterfield,1997,Fugit perferendis est quam sunt porro vel rerum.
-book,Melty Breaker,Montana Dickinson Sr.,1991,Perferendis harum fuga corporis.
-book,Winter Pie,Mr. Syble Kuhn,1970,Incidunt molestias deserunt laudantium.
-album,Goodbye Utopia,Orion Spencer,1962,Praesentium enim pariatur voluptatem sed quod dolorum.
-album,Green Select,Berneice Jenkins,1957,Hic repudiandae molestiae id nulla aliquid maiores necessitatibus.
-book,Blacktop Enlightenment,Seamus D'Amore,1928,Ea id cumque et pariatur magni nemo dolorem.
-album,Express Extract,Dorothy Jast I,1969,Dolores dolorum aut ea aperiam et voluptatem.
-album,Winter Been,Mackenzie Wilkinson,1932,Culpa repudiandae et at sint et amet fugiat et.
-book,Heart Mug,Orpha Douglas,2009,Qui voluptas alias quia.
-album,Blue Treat,Eliseo Gorczany,1979,Sit est quis veniam saepe.
-book,Hello Town,Laury Walter,2005,Est sed ut asperiores sed fugiat.
-album,Blacktop Choice,Casey Feil,2008,Temporibus ex maxime labore quam et natus quia ipsum.
-book,Huggy Star,Nigel Lesch DVM,1962,Voluptatem ea aspernatur nesciunt ipsa quis error corporis placeat.
+album,Digital Slide Switch,Dark Storm X,1936,Re-engineered modular intranetrecontextualize turn-key communities
+book,Digital Piezoelectric device,Red Darkside Strange,1984,Vision-oriented mission-critical softwaremesh dot-com solutions
+book,1080p Printed Circuit Board,Supah Ares Lord,1954,Vision-oriented stable neural-netincentivize B2B architectures
+book,Redundant crystal,The Spider,2003,Assimilated value-added workforcetarget real-time synergies
+movie,Multi-byte Power Cord,Feral of Hearts,2009,Stand-alone mission-critical functionalitiesrepurpose next-generation partnerships
+book,Solid state Keypad,Kang III,1928,Polarised composite encodinginnovate customized functionalities
+book,Cross-platform DIP Switch,Supah Two-Face,2002,Visionary actuating algorithmsynthesize efficient action-items
+book,Cross-platform Power Cord,Ben Girl,1919,Re-contextualized full-range productgenerate transparent bandwidth
+book,Primary Socket,Cyborg Nova,2008,Future-proofed actuating help-deskvisualize granular systems
+album,Neural Printed Circuit Board,Walrus IX,1981,Future-proofed dedicated pricing structurescale cross-platform niches
+book,Redundant crystal,Vindicator Brain,1950,Multi-channelled discrete productivitydeploy holistic ROI
+album,1080p Slide Switch,Magnificent Darkhawk,1984,Progressive actuating hardwareaggregate cross-platform supply-chains
+album,Cross-platform Circuit Breaker,Mr Skaar,2001,Object-based multimedia moratoriumevolve B2B architectures
+album,Back-end DIP Switch,The Spawn,1960,Exclusive multi-tasking hierarchyevolve bricks-and-clicks interfaces
+album,Haptic crystal,Booster Gold,1933,Up-sized full-range implementationintegrate value-added technologies
+movie,Open-source Terminal,Sunspot,1925,Pre-emptive fresh-thinking orchestrationrevolutionize B2C methodologies
+movie,Online DIP Switch,Mr Trickster,2011,Enhanced non-volatile hardwarescale value-added users
+album,Multi-byte Ultrasonic Motor,Maverick,2002,Proactive coherent secured linerecontextualize dot-com networks
+album,Solid state Toggle Switch,Agent Blizzard,1935,Robust encompassing process improvementstrategize turn-key metrics
+book,Solid state DIP Switch,ERG Spirit,1958,Optional multi-tasking info-mediariesstreamline value-added paradigms
+book,Digital Toggle Switch,Supah Morph,1996,Phased content-based softwarestrategize sticky partnerships
+book,Neural DIP Switch,Hollow,1925,Seamless context-sensitive instruction setsyndicate front-end web services
+album,Optical Slide Switch,Doctor Violet,1961,Ameliorated explicit collaborationbenchmark out-of-the-box paradigms
+movie,Redundant Fuse,Arclight III,1935,Versatile hybrid knowledge basebenchmark efficient infomediaries
+book,Solid state Ultrasonic Motor,Banshee,1977,Focused national benchmarkengage one-to-one e-business
+book,Open-source Circuit Breaker,Doctor Hawk,1999,Stand-alone 24/7 capabilityrevolutionize killer content
+movie,Optical Piezoelectric device,Mr Quantum IX,1998,Re-engineered multi-tasking projectiondrive synergistic eyeballs
+book,Online Toggle Switch,Doctor Ghost,1924,Re-contextualized impactful budgetary managementfacilitate innovative e-markets
+movie,1080p Fuse,The Ink,1986,Visionary hybrid interfacedeploy vertical methodologies
+book,Auxiliary Keypad,Doc Samson Man,1940,Switchable solution-oriented capacityrevolutionize transparent users
+album,Solid state Socket,Ultra Goblin Queen,1929,Optimized impactful firmwareaggregate transparent mindshare
+album,1080p Power Cord,Redeemer,1985,Streamlined real-time internet solutionunleash robust ROI
+movie,Multi-byte Slide Switch,Giant Booster Gold Eyes,1920,Extended clear-thinking orchestrationgrow 24/365 systems
+album,Optical Slide Switch,Aztar the Hunter,1935,Compatible even-keeled moratoriumrecontextualize customized systems
+movie,Wireless Power Cord,The Nathan Petrelli Girl,1985,Virtual directional accessrepurpose value-added networks
+book,Digital Ultrasonic Motor,Green Lyja Brain,2008,Expanded impactful superstructureexploit turn-key synergies
+album,Solid state Ultrasonic Motor,Warbird,1987,Persistent user-facing Graphic Interfacemesh robust architectures
+movie,Mobile Printed Circuit Board,Bushido Claw,1921,Seamless leading edge functiondrive dynamic e-markets
+book,Multi-byte Socket,Agent Colin Wagner Brain,2010,Diverse object-oriented firmwareengage extensible e-business
+movie,Multi-byte Power Cord,Red Metron,2004,Seamless zero tolerance projectionstreamline scalable web-readiness
+movie,Wireless Footswitch,Agent Chromos,1980,Adaptive national hubbrand interactive e-tailers
+movie,Solid state Power Cord,Agent Toad Girl,1984,Managed needs-based attitudereinvent strategic models
+movie,Cross-platform Fuse,Venom XI,2014,Compatible didactic archivematrix visionary deliverables
+album,Virtual crystal,Doctor Yellowjacket,1975,Grass-roots tangible approachfacilitate cutting-edge metrics
+movie,Virtual Circuit Breaker,Cyborg Jolt XI,1981,Advanced systemic coremaximize virtual technologies
+album,Auxiliary Toggle Switch,Captain Venom Ivy,1996,Versatile fault-tolerant task-forceengineer B2C supply-chains
+album,Neural Toggle Switch,Atom Girl,1937,Re-engineered 3rd generation utilisationenable best-of-breed web services
+book,Digital crystal,Cyborg Winter Soldier,1966,Face to face solution-oriented budgetary managementorchestrate out-of-the-box ROI
+album,Neural Piezoelectric device,Proto-Goblin,1941,User-centric analyzing task-forcescale impactful initiatives
+book,Digital Ultrasonic Motor,General Shrinking Violet,1965,Realigned asynchronous projectscale frictionless e-markets
+album,Digital Fuse,Doctor Zoom Strike,1981,Profound optimal knowledge basesyndicate interactive infrastructures
+movie,Digital Circuit Breaker,Punisher II,1998,Virtual encompassing infrastructuremorph out-of-the-box bandwidth
+album,Bluetooth Piezoelectric device,Toxin,1953,Implemented stable pricing structurematrix leading-edge e-commerce
+movie,Online Toggle Switch,Yellow,2007,Compatible fresh-thinking policygenerate viral partnerships
+book,1080p crystal,Illustrious Jack-Jack,1925,Digitized tertiary projectvisualize innovative deliverables
+book,1080p Fuse,Blink,1932,Synergized fault-tolerant coreincubate out-of-the-box functionalities
+book,Cross-platform Socket,Agent Rogue Girl,1946,User-friendly secondary leveragedisintermediate impactful infomediaries
+album,Haptic Piezoelectric device,Evilhawk,1946,Triple-buffered client-server accesstransform open-source functionalities
+movie,Multi-byte Fuse,Venom,2006,Stand-alone neutral task-forcemorph 24/365 infrastructures
+book,Optical Socket,Hyperion,1998,Decentralized systematic intranetextend world-class methodologies
+book,Optical Toggle Switch,Magnificent Tiger Shark I,1967,Virtual attitude-oriented help-deskoptimize frictionless bandwidth
+movie,Wireless Fuse,Cyborg Cy-Gor,1989,Versatile motivating moratoriumdisintermediate B2C systems
+book,Back-end Power Cord,Rocket Raccoon,1943,Open-source client-server firmwarewhiteboard enterprise paradigms
+book,Digital Keypad,Molten Man II,1998,Reactive multimedia open systemengineer holistic platforms
+album,Mobile Footswitch,Dark Garbage Claw,1939,Devolved national knowledge userreinvent e-business users
+movie,1080p Slide Switch,Evilhawk,1960,Upgradable explicit intranetengineer plug-and-play initiatives
+album,Cross-platform DIP Switch,Agent Carnage Claw,1949,Optional grid-enabled definitionmatrix seamless functionalities
+movie,Optical Footswitch,Cyborg Gog,1940,User-friendly client-server complexityimplement bricks-and-clicks e-commerce
+album,Optical Toggle Switch,Evilhawk,1968,Organized motivating attitudeimplement innovative web services
+movie,Online Socket,Shocker,2019,Monitored systematic forecastenvisioneer user-centric markets
+movie,Neural Piezoelectric device,General Wildfire Machine,1929,Managed tertiary standardizationexpedite web-enabled partnerships
+movie,Open-source Keypad,Supah Brother Voodoo,1990,Multi-layered multimedia forecastembrace web-enabled interfaces
+album,Multi-byte Keypad,Red Thing,1968,Virtual real-time structuremaximize efficient interfaces
+album,Mobile Slide Switch,Ultra Warlock,1929,Operative contextually-based matrixmaximize sticky models
+movie,Back-end DIP Switch,Plastique,2001,Horizontal 24/7 groupwaresyndicate mission-critical web-readiness
+album,Solid state Circuit Breaker,Giant Evilhawk XI,1987,Automated optimizing artificial intelligenceengage virtual synergies
+book,Mobile Slide Switch,Supah Doomsday,2013,Vision-oriented composite throughputbrand B2B vortals
+book,Solid state DIP Switch,Cyborg Ghost Wolf,1941,Public-key bifurcated approachutilize proactive convergence
+book,Primary Keypad,Dark Deathstroke,1969,Implemented needs-based moratoriumengineer leading-edge deliverables
+book,Haptic Power Cord,Giganta I,1958,Open-source encompassing neural-netcultivate user-centric applications
+album,Redundant Printed Circuit Board,Apocalypse I,1991,Upgradable multimedia system engineembrace proactive metrics
+album,Cross-platform Terminal,Quill,1989,Monitored national encodingproductize cross-platform web services
+album,Solid state Ultrasonic Motor,Loki,1991,Customer-focused tangible time-frameharness customized users
+movie,Optical Power Cord,Cyborg Shrinking Violet Knight,1959,Networked systematic framecultivate B2B e-commerce
+movie,Digital Printed Circuit Board,Longshot Strike,1939,Quality-focused background internet solutionmorph strategic paradigms
+movie,Wireless Fuse,Captain Hybrid,2015,De-engineered global knowledge useriterate end-to-end e-markets
+movie,Virtual Socket,Vindicator II,1993,Grass-roots tangible challengesynergize global initiatives
+movie,Neural Terminal,Mr Hercules,1920,Exclusive user-facing functiondisintermediate integrated architectures
+book,Online DIP Switch,Corsair,1940,Networked logistical internet solutionrevolutionize compelling architectures
+book,Primary crystal,Corsair,1967,User-friendly maximized circuitbenchmark leading-edge synergies
+movie,Virtual Footswitch,Green Carnage the Fated,1944,Optimized directional Graphic Interfacedisintermediate cutting-edge ROI
+movie,1080p Terminal,Cyborg Yellow Machine,1974,Realigned regional encryptionengage turn-key platforms
+book,Wireless Socket,Moonstone,1944,Public-key heuristic task-forcescale interactive bandwidth
+album,Optical Fuse,Ultra Deadpool Ivy,1996,Integrated logistical portaltransition ubiquitous relationships
+movie,Solid state Slide Switch,Mr Mockingbird II,1960,Total client-server solutionempower enterprise relationships
+book,Neural crystal,Question,2009,Self-enabling explicit hierarchyexploit frictionless experiences
+album,Cross-platform Terminal,Giant Wolverine,2002,Ergonomic bi-directional conceptharness magnetic mindshare
+album,Virtual Ultrasonic Motor,Firebird,1999,Team-oriented asynchronous process improvementstrategize wireless schemas
+book,Mobile DIP Switch,Cypher Brain,2002,Decentralized 4th generation analyzerarchitect e-business schemas
+book,Neural Power Cord,Snowbird Dragon,2017,Reactive static capabilityrecontextualize visionary mindshare
diff --git a/db/migrate/20190422233839_create_works.rb b/db/migrate/20190422233839_create_works.rb
new file mode 100644
index 0000000000..361b5190e2
--- /dev/null
+++ b/db/migrate/20190422233839_create_works.rb
@@ -0,0 +1,13 @@
+class CreateWorks < ActiveRecord::Migration[5.2]
+ def change
+ create_table :works do |t|
+ t.string :category
+ t.string :title
+ t.string :creator
+ t.integer :publication_year
+ t.text :description
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20190422233957_create_users.rb b/db/migrate/20190422233957_create_users.rb
new file mode 100644
index 0000000000..45ed363af2
--- /dev/null
+++ b/db/migrate/20190422233957_create_users.rb
@@ -0,0 +1,10 @@
+class CreateUsers < ActiveRecord::Migration[5.2]
+ def change
+ create_table :users do |t|
+ t.string :username
+ t.datetime :date_joined
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20190422234031_create_votes.rb b/db/migrate/20190422234031_create_votes.rb
new file mode 100644
index 0000000000..7ee86107b2
--- /dev/null
+++ b/db/migrate/20190422234031_create_votes.rb
@@ -0,0 +1,10 @@
+class CreateVotes < ActiveRecord::Migration[5.2]
+ def change
+ create_table :votes do |t|
+ t.integer :user_id
+ t.integer :work_id
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/migrate/20190423004633_change_data_types_in_work_table.rb b/db/migrate/20190423004633_change_data_types_in_work_table.rb
new file mode 100644
index 0000000000..d3a5a8c7cd
--- /dev/null
+++ b/db/migrate/20190423004633_change_data_types_in_work_table.rb
@@ -0,0 +1,11 @@
+class ChangeDataTypesInWorkTable < ActiveRecord::Migration[5.2]
+ def up
+ change_column :works, :description, :text
+ change_column :works, :publication_year, 'integer USING CAST(publication_year AS integer)'
+ end
+
+ def down
+ change_column :works, :description, :string
+ change_column :works, :publication_year, :string
+ end
+end
diff --git a/db/migrate/20190423004700_change_data_types_in_user_table.rb b/db/migrate/20190423004700_change_data_types_in_user_table.rb
new file mode 100644
index 0000000000..3c19a352ea
--- /dev/null
+++ b/db/migrate/20190423004700_change_data_types_in_user_table.rb
@@ -0,0 +1,11 @@
+class ChangeDataTypesInUserTable < ActiveRecord::Migration[5.2]
+ def up
+ remove_column :users, :date_joined
+ add_column :users, :date_joined, :datetime
+end
+
+ def down
+ remove_column :users, :date_joined
+ add_column :users, :date_joined, :string
+ end
+end
diff --git a/db/migrate/20190423004718_change_data_types_in_vote_table.rb b/db/migrate/20190423004718_change_data_types_in_vote_table.rb
new file mode 100644
index 0000000000..81b54c1cdc
--- /dev/null
+++ b/db/migrate/20190423004718_change_data_types_in_vote_table.rb
@@ -0,0 +1,11 @@
+class ChangeDataTypesInVoteTable < ActiveRecord::Migration[5.2]
+ def up
+ change_column :votes, :user_id, 'integer USING CAST(user_id AS integer)'
+ change_column :votes, :work_id, 'integer USING CAST(work_id AS integer)'
+ end
+
+ def down
+ change_column :votes, :user_id, :string
+ change_column :votes, :work_id, :string
+ end
+end
diff --git a/db/migrate/20190424174048_add_column.rb b/db/migrate/20190424174048_add_column.rb
new file mode 100644
index 0000000000..f3ff619715
--- /dev/null
+++ b/db/migrate/20190424174048_add_column.rb
@@ -0,0 +1,5 @@
+class AddColumn < ActiveRecord::Migration[5.2]
+ def change
+ add_column :votes, :date_voted, :datetime
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
new file mode 100644
index 0000000000..2ded444b4f
--- /dev/null
+++ b/db/schema.rb
@@ -0,0 +1,43 @@
+# 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: 2019_04_24_174048) do
+
+ # These are extensions that must be enabled in order to support this database
+ enable_extension "plpgsql"
+
+ create_table "users", force: :cascade do |t|
+ t.string "username"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.datetime "date_joined"
+ end
+
+ create_table "votes", force: :cascade do |t|
+ t.integer "user_id"
+ t.integer "work_id"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.datetime "date_voted"
+ end
+
+ create_table "works", force: :cascade do |t|
+ t.string "category"
+ t.string "title"
+ t.string "creator"
+ t.integer "publication_year"
+ t.text "description"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+end
diff --git a/db/seeds.rb b/db/seeds.rb
new file mode 100644
index 0000000000..15ef987ea3
--- /dev/null
+++ b/db/seeds.rb
@@ -0,0 +1,33 @@
+# This file should contain all the record creation needed to seed the database with its default values.
+# The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
+#
+# Examples:
+#
+# movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
+# Character.create(name: 'Luke', movie: movies.first)
+
+require 'csv'
+
+MEDIA_FILE = Rails.root.join('db', '', 'media_seeds.csv')
+puts "Loading raw media data from #{MEDIA_FILE}"
+
+media_failures = []
+CSV.foreach(MEDIA_FILE, :headers => true) do |row|
+ work = Work.new
+ work.category = row['category']
+ work.title = row['title']
+ work.creator = row['creator']
+ work.publication_year = row['publication_year']
+ work.description = row['description']
+
+ successful = work.save
+ if !successful
+ media_failures << work
+ puts "Failed to save media: #{work.inspect}"
+ else
+ puts "Created media: #{work.inspect}"
+ end
+end
+
+puts "Added #{Work.count} media records"
+puts "#{media_failures.length} media failed to save"
\ No newline at end of file
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..625900f9d8
--- /dev/null
+++ b/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "MediaRanker",
+ "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/storage/.keep b/storage/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb
new file mode 100644
index 0000000000..176c5d1da3
--- /dev/null
+++ b/test/application_system_test_case.rb
@@ -0,0 +1,4 @@
+require "test_helper"
+
+class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
+end
diff --git a/test/controllers/.keep b/test/controllers/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test/controllers/landing_controller_test.rb b/test/controllers/landing_controller_test.rb
new file mode 100644
index 0000000000..02d660732e
--- /dev/null
+++ b/test/controllers/landing_controller_test.rb
@@ -0,0 +1,10 @@
+ require "test_helper"
+
+ describe LandingController do
+
+ it "should get index" do
+ get root_path
+ value(response).must_be :successful?
+ end
+
+ end
diff --git a/test/controllers/sessions_controller_test.rb b/test/controllers/sessions_controller_test.rb
new file mode 100644
index 0000000000..a57af1bae9
--- /dev/null
+++ b/test/controllers/sessions_controller_test.rb
@@ -0,0 +1,14 @@
+require "test_helper"
+
+describe SessionsController do
+ it "should get login" do
+ get login_path
+ must_respond_with :success
+ end
+
+ it "should get logout" do
+ post logout_path
+ must_respond_with :success
+ end
+
+end
diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb
new file mode 100644
index 0000000000..4cc9baa3ae
--- /dev/null
+++ b/test/controllers/users_controller_test.rb
@@ -0,0 +1,15 @@
+
+require "test_helper"
+
+describe UsersController do
+ it "should get index" do
+ get users_path
+ must_respond_with :success
+end
+
+ it "should get show" do
+ get user_path(users(:one).id)
+ must_respond_with :success
+ end
+
+end
\ No newline at end of file
diff --git a/test/controllers/works_controller_test.rb b/test/controllers/works_controller_test.rb
new file mode 100644
index 0000000000..6641ccd891
--- /dev/null
+++ b/test/controllers/works_controller_test.rb
@@ -0,0 +1,24 @@
+require "test_helper"
+
+describe WorksController do
+ it "should get index" do
+ get works_path
+ must_respond_with :success
+ end
+
+ it "should get show" do
+ get work_path(works(:book1).id)
+ must_respond_with :success
+ end
+
+ it "should get new" do
+ get new_work_path
+ must_respond_with :success
+ end
+
+ it "should get edit" do
+ get edit_work_path(works(:book2).id)
+ must_respond_with :success
+ end
+
+end
\ No newline at end of file
diff --git a/test/fixtures/.keep b/test/fixtures/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test/fixtures/files/.keep b/test/fixtures/files/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml
new file mode 100644
index 0000000000..5c0bb52747
--- /dev/null
+++ b/test/fixtures/users.yml
@@ -0,0 +1,9 @@
+# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+one:
+ username: superfresh
+ date_joined: 4-10-2019
+
+two:
+ username: extrafresh
+ date_joined: 10-24-2018
diff --git a/test/fixtures/votes.yml b/test/fixtures/votes.yml
new file mode 100644
index 0000000000..b17d1a449f
--- /dev/null
+++ b/test/fixtures/votes.yml
@@ -0,0 +1,12 @@
+# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+vote1:
+ user: one
+ work: book1
+
+vote2:
+ user: one
+ work: book1
+
+vote3:
+ user: two
+ work: book2
\ No newline at end of file
diff --git a/test/fixtures/works.yml b/test/fixtures/works.yml
new file mode 100644
index 0000000000..b88522c1fa
--- /dev/null
+++ b/test/fixtures/works.yml
@@ -0,0 +1,28 @@
+# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+book1:
+ category: book
+ title: Nest Building
+ creator: Big Bird
+ publication_year: 2004
+ description: This book is amazing
+
+book2:
+ category: book
+ title: Recipes with Salt
+ creator: Bingo, the Farmer's Dog
+ publication_year: 2012
+ description: Srsly you gotta read this
+
+album1:
+ category: album
+ title: Zoo Noises
+ creator: Literally the Animals at the Zoo
+ publication_year: 1963
+ description: So much variety here
+
+album2:
+ category: album
+ title: Learn Spanish in Your Sleep II
+ creator: Subliminal Language Courses
+ publication_year: 1966
+ description: Works best with headphones
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/user_test.rb b/test/models/user_test.rb
new file mode 100644
index 0000000000..caa4d78d11
--- /dev/null
+++ b/test/models/user_test.rb
@@ -0,0 +1,54 @@
+require "test_helper"
+
+describe User do
+ let(:user) { users(:one) }
+
+ describe 'validations' do
+ it 'is valid when all fields are present' do
+ result = user.valid?
+ expect(result).must_equal true
+ end
+
+ it 'must have a username' do
+ user.username = nil
+ result = user.valid?
+
+ expect(result).must_equal false
+ end
+
+ it 'must have a unique username' do
+ user2 = User.new(username: "superfresh")
+ result = user2.save
+
+ expect(result).must_equal false
+ end
+
+ end
+
+ describe 'relationships' do
+ it 'can have many votes' do
+ votes = user.votes
+
+ expect(votes.length).must_equal 2
+ votes.each do |vote|
+ expect(vote).must_be_instance_of Vote
+ end
+ end
+
+ it 'can have zero votes' do
+ new_user = User.new
+ votes = new_user.votes
+
+ expect(votes.length).must_equal 0
+ end
+ end
+
+ describe 'has_voted?' do
+ it 'can return true if user has already voted on the work' do
+ work = user.votes.first.work_id
+ result = user.has_voted?(work)
+
+ expect(result).wont_be_nil
+ end
+ end
+end
diff --git a/test/models/vote_test.rb b/test/models/vote_test.rb
new file mode 100644
index 0000000000..3ed5a8e0e0
--- /dev/null
+++ b/test/models/vote_test.rb
@@ -0,0 +1,39 @@
+require "test_helper"
+
+describe Vote do
+ let(:vote) { votes(:vote1) }
+
+ describe 'validations' do
+ it 'is valid when all fields are present' do
+ result = vote.valid?
+ expect(result).must_equal true
+ end
+
+ it 'requires user_id' do
+ vote.user_id = nil
+ result = vote.valid?
+ expect(result).must_equal false
+ end
+
+ it 'requires work_id' do
+ vote.work_id = nil
+ result = vote.valid?
+ expect(result).must_equal false
+ end
+ end
+
+ describe 'relationships' do
+ let(:user) { users(:one) }
+ let(:work) { works(:book1) }
+
+ it 'belongs to a user' do
+ user_test = vote.user_id
+ expect(user_test).must_equal user.id
+ end
+
+ it 'belongs to a work' do
+ work_test = vote.work_id
+ expect(work_test).must_equal work.id
+ end
+ end
+end
diff --git a/test/models/work_test.rb b/test/models/work_test.rb
new file mode 100644
index 0000000000..182070c84d
--- /dev/null
+++ b/test/models/work_test.rb
@@ -0,0 +1,126 @@
+require "test_helper"
+
+describe Work do
+ let(:work) { works(:book1) }
+
+ describe 'validations' do
+ it 'is valid when all fields are present' do
+ result = work.valid?
+ expect(result).must_equal true
+ end
+
+ it 'must have a title' do
+ work.title = nil
+ result = work.valid?
+
+ expect(result).must_equal false
+ end
+ end
+
+ describe 'relationships' do
+ it 'can have many votes' do
+ votes = work.votes
+
+ expect(votes.length).must_equal 2
+ votes.each do |vote|
+ expect(vote).must_be_instance_of Vote
+ end
+ end
+ end
+
+ describe 'vote_count' do
+ let(:work2) { works(:album2) }
+
+ it 'can calculate the number of votes' do
+ num_votes = work.vote_count
+ expect(num_votes).must_equal 2
+ end
+
+ it 'will return 0 for no votes' do
+ num_votes = work2.vote_count
+ expect(num_votes).must_equal 0
+ end
+
+ end
+
+ describe 'top_media' do
+ it 'can return the work with the most number of votes' do
+ work = Work.top_media
+ expect(work.title).must_equal "Nest Building"
+ end
+
+ it 'will return nil when no works are available to spotlight' do
+ Work.find_by(title: "Nest Building").delete
+ Work.find_by(title: "Recipes with Salt").delete
+ Work.find_by(title: "Zoo Noises").delete
+ Work.find_by(title: "Learn Spanish in Your Sleep II").delete
+
+ expect(Work.top_media).must_be_nil
+ end
+
+ it 'will return first media available when no votes overall' do
+ Vote.all.first.delete
+
+ expect(Work.top_media).must_be_instance_of Work
+ end
+
+ it 'will return first media when there is a tie' do
+ vote = Vote.new
+ vote.user = users(:two)
+ vote.work = works(:book2)
+
+ expect(Work.top_media.title).must_equal "Nest Building"
+ end
+ end
+
+ describe 'category_list' do
+ before do
+ @books = Work.category_list("book")
+ @albums = Work.category_list("album")
+ end
+
+ it 'can display the list of works for a specific category' do
+ expect(@books.first).must_be_instance_of Work
+ expect(@books.first.category).must_equal "book"
+ expect(@books.length).must_equal 2
+
+ expect(@albums.first).must_be_instance_of Work
+ expect(@albums.first.category).must_equal "album"
+ expect(@albums.length).must_equal 2
+ end
+
+ it 'can return the list sorted by number of votes in descending order' do
+ expect(@books.first.vote_count).must_equal 2
+ expect(@books.last.vote_count).must_equal 1
+
+ expect(@albums.first.vote_count).must_equal 0
+ expect(@albums.last.vote_count).must_equal 0
+ end
+
+ it 'will return an empty array if there are no works in the category' do
+ movies = Work.category_list("movie")
+ expect(movies).must_equal []
+ end
+ end
+
+ describe 'top_ten' do
+ it 'will return an array of 10 elements if there are 10 or more works' do
+ 10.times do
+ Work.create(title: "Unique Book", category: "book")
+ end
+
+ top_ten_books = Work.top_ten("book")
+ expect(top_ten_books.length).must_equal 10
+ end
+
+ it 'will return an array of n elements if n is less than 10 in category' do
+ top_ten_books = Work.top_ten("album")
+ expect(top_ten_books.length).must_equal 2
+ end
+
+ it 'will return 0 if there are no works in the category' do
+ top_ten_books = Work.top_ten("movie")
+ expect(top_ten_books.length).must_equal 0
+ end
+ end
+end
\ No newline at end of file
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..3f7dc7d3ed
--- /dev/null
+++ b/test/test_helper.rb
@@ -0,0 +1,24 @@
+ENV["RAILS_ENV"] = "test"
+require File.expand_path("../../config/environment", __FILE__)
+require "rails/test_help"
+require "minitest/rails"
+require "minitest/reporters" # for Colorized output
+# For colorful output!
+Minitest::Reporters.use!(
+ Minitest::Reporters::SpecReporter.new,
+ ENV,
+ Minitest.backtrace_filter
+)
+
+# To add Capybara feature tests add `gem "minitest-rails-capybara"`
+# to the test group in the Gemfile and uncomment the following:
+# require "minitest/rails/capybara"
+
+# Uncomment for awesome colorful output
+# require "minitest/pride"
+
+class ActiveSupport::TestCase
+ # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
+ fixtures :all
+ # Add more helper methods to be used by all tests here...
+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