diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..60192930d --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,32 @@ +Neccesary checkmarks: + + - [ ] All Tests are Passing + - [ ] The code will run locally + +Type of change + + - [ ] New feature + - [ ] Bug Fix + +Implements/Fixes: + + description closes # + +Check the correct boxes + + - [ ] This broke nothing + - [ ] This broke some stuff + - [ ] This broke everything + +Testing Changes + + - [ ] No Tests have been changed + - [ ] Some Tests have been changed + - [ ] All of the Tests have been changed(Please describe what in the world happened) + +Checklist: + + - [ ] My code has no unused/commented out code + - [ ] I have reviewed my code + - [ ] I have commented my code, particularly in hard-to-understand areas + - [ ] I have fully tested my code diff --git a/.gitignore b/.gitignore index e16dc71d2..6bef5482f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ # 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' - +/coverage # Ignore bundler config. /.bundle diff --git a/.rspec b/.rspec new file mode 100644 index 000000000..c99d2e739 --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--require spec_helper diff --git a/Gemfile b/Gemfile index a8a68a722..b6ba227b1 100644 --- a/Gemfile +++ b/Gemfile @@ -1,31 +1,33 @@ -source "https://rubygems.org" +# frozen_string_literal: true + +source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby "3.2.2" +ruby '3.2.2' # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" -gem "rails", "~> 7.0.4", ">= 7.0.4.2" +gem 'rails', '~> 7.0.4', '>= 7.0.4.2' # The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] -gem "sprockets-rails" +gem 'sprockets-rails' # Use postgresql as the database for Active Record -gem "pg", "~> 1.1" +gem 'pg', '~> 1.1' # Use the Puma web server [https://github.com/puma/puma] -gem "puma", "~> 5.0" +gem 'puma', '~> 5.0' # Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails] -gem "importmap-rails" +gem 'importmap-rails' # Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev] -gem "turbo-rails" +gem 'turbo-rails' # Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev] -gem "stimulus-rails" +gem 'stimulus-rails' # Build JSON APIs with ease [https://github.com/rails/jbuilder] -gem "jbuilder" +gem 'jbuilder' # Use Redis adapter to run Action Cable in production # gem "redis", "~> 4.0" @@ -37,10 +39,10 @@ gem "jbuilder" # gem "bcrypt", "~> 3.1.7" # Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] +gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby] # Reduces boot times through caching; required in config/boot.rb -gem "bootsnap", require: false +gem 'bootsnap', require: false # Use Sass to process CSS # gem "sassc-rails" @@ -50,24 +52,31 @@ gem "bootsnap", require: false group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem - gem "pry" + gem 'factory_bot_rails' + gem 'faker' + gem 'pry' end group :development do # Use console on exceptions pages [https://github.com/rails/web-console] - gem "web-console" + gem 'web-console' # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler] # gem "rack-mini-profiler" # Speed up commands on slow machines / big apps [https://github.com/rails/spring] # gem "spring" - gem "rubocop-rails" + gem 'rubocop-rails' end group :test do - gem "rspec-rails" - gem "capybara" - gem "launchy" - gem "simplecov" -end \ No newline at end of file + gem 'capybara' + gem 'launchy' + gem 'rspec-rails' + gem 'shoulda-matchers' + gem 'simplecov' + gem 'vcr' + gem 'webmock' +end + +gem 'faraday' diff --git a/Gemfile.lock b/Gemfile.lock index b54ee32ad..69dc1a119 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -69,6 +69,7 @@ GEM addressable (2.8.4) public_suffix (>= 2.0.2, < 6.0) ast (2.4.2) + base64 (0.1.1) bindex (0.8.1) bootsnap (1.16.0) msgpack (~> 1.2) @@ -84,13 +85,28 @@ GEM xpath (~> 3.2) coderay (1.1.3) concurrent-ruby (1.2.2) + crack (0.4.5) + rexml crass (1.0.6) date (3.3.3) diff-lcs (1.5.0) docile (1.4.0) erubi (1.12.0) + factory_bot (6.2.1) + activesupport (>= 5.0.0) + factory_bot_rails (6.2.0) + factory_bot (~> 6.2.0) + railties (>= 5.0.0) + faker (3.2.1) + i18n (>= 1.8.11, < 2) + faraday (2.7.11) + base64 + faraday-net_http (>= 2.0, < 3.1) + ruby2_keywords (>= 0.0.4) + faraday-net_http (3.0.2) globalid (1.1.0) activesupport (>= 5.0) + hashdiff (1.0.1) i18n (1.14.1) concurrent-ruby (~> 1.0) importmap-rails (1.2.1) @@ -213,6 +229,9 @@ GEM rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) ruby-progressbar (1.13.0) + ruby2_keywords (0.0.5) + shoulda-matchers (5.3.0) + activesupport (>= 5.2.0) simplecov (0.22.0) docile (~> 1.1) simplecov-html (~> 0.11) @@ -237,11 +256,16 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.4.2) + vcr (6.2.0) web-console (4.2.0) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) + webmock (3.19.1) + addressable (>= 2.8.0) + crack (>= 0.3.2) + hashdiff (>= 0.4.0, < 2.0.0) websocket-driver (0.7.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) @@ -250,12 +274,16 @@ GEM zeitwerk (2.6.8) PLATFORMS + arm64-darwin-21 arm64-darwin-22 x86_64-darwin-21 DEPENDENCIES bootsnap capybara + factory_bot_rails + faker + faraday importmap-rails jbuilder launchy @@ -265,12 +293,15 @@ DEPENDENCIES rails (~> 7.0.4, >= 7.0.4.2) rspec-rails rubocop-rails + shoulda-matchers simplecov sprockets-rails stimulus-rails turbo-rails tzinfo-data + vcr web-console + webmock RUBY VERSION ruby 3.2.2p53 diff --git a/Rakefile b/Rakefile index 9a5ea7383..488c551fe 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,8 @@ +# frozen_string_literal: true + # 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" +require_relative 'config/application' Rails.application.load_tasks diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 288b9ab71..2799dc9c2 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -13,3 +13,7 @@ *= require_tree . *= require_self */ +.search_field { + text-align: center; + opacity: 0.6; +} \ No newline at end of file diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb index d67269728..9aec23053 100644 --- a/app/channels/application_cable/channel.rb +++ b/app/channels/application_cable/channel.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationCable class Channel < ActionCable::Channel::Base end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb index 0ff5442f4..8d6c2a1bf 100644 --- a/app/channels/application_cable/connection.rb +++ b/app/channels/application_cable/connection.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationCable class Connection < ActionCable::Connection::Base end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 09705d12a..405638b59 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,2 +1,5 @@ +# frozen_string_literal: true + class ApplicationController < ActionController::Base + add_flash_types :alert end diff --git a/app/controllers/movies_controller.rb b/app/controllers/movies_controller.rb new file mode 100644 index 000000000..2765cc316 --- /dev/null +++ b/app/controllers/movies_controller.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class MoviesController < ApplicationController + def index + @user = User.find(params[:user_id]) + search_query = params[:search] + + movies = if search_query.present? + MovieService.new.search_movies(search_query) + else + MovieService.new.top_rated_movies + end + + @movies = movies[:results] + end + + def show + @user = User.find(params[:user_id]) + movie_id = params[:id] + movie = MovieService.new.movie_details(movie_id) + cast = MovieService.new.cast(movie_id) + reviews = MovieService.new.movie_reviews(movie_id) + + @movie = Movie.new(movie) + @cast = cast[:cast].first(10) + @reviews = reviews[:results] + end +end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 000000000..8918016d1 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +class UsersController < ApplicationController + def index + @user = User.find(params[:user_id]) + end + + def new; end + + def create + user = User.new(user_params) + if !user.save + flash.now[:alert] = if params.require(:user)[:name] == '' || params.require(:user)[:email] == '' + 'Missing Inputs' + else + 'Email already in use' + end + render :new + else + redirect_to user_path(user) + end + end + + def show + @user = User.find(params[:id]) + end + + private + + def user_params + params.require(:user).permit(:name, :email) + end +end diff --git a/app/controllers/viewing_party_controller.rb b/app/controllers/viewing_party_controller.rb new file mode 100644 index 000000000..cc0409f11 --- /dev/null +++ b/app/controllers/viewing_party_controller.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +class ViewingPartyController < ApplicationController + def new + @host = User.find(params[:user_id]) + @movie = Movie.movie + @users = User.where.not(id: params[:user_id]) + end + + def create + movie = Movie.movie + duration = params[:duration] + start_time = params[:start_time] + date = params[:when] + + if duration.blank? || start_time.blank? || date.blank? + flash[:alert] = "Duration, Start Time, and Date are required fields" + redirect_to new_user_movie_viewing_party_path + return + end + + party = ViewingParty.create!( + movie_id: movie.id, + movie_title: movie.title, + movie_image: movie.img, + duration: duration, + date: date, + start_time: start_time + ) + + host = User.find(params[:user_id]) + + if params[:guests].nil? + flash[:alert] = "Add guests to the party" + redirect_to new_user_movie_viewing_party_path + return + end + + users = params[:guests].map do |guest| + User.find(guest) + end + + UsersViewingParty.create!(user_id: host.id, viewing_party_id: party.id, hosting?: true) + users.each do |user| + UsersViewingParty.create!(user_id: user.id, viewing_party_id: party.id) + end + + redirect_to user_path(host) + end +end diff --git a/app/controllers/welcome_controller.rb b/app/controllers/welcome_controller.rb new file mode 100644 index 000000000..7f77f38fc --- /dev/null +++ b/app/controllers/welcome_controller.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class WelcomeController < ApplicationController + def index + @users = User.all + end +end diff --git a/app/facades/movie_facade.rb b/app/facades/movie_facade.rb new file mode 100644 index 000000000..d769685aa --- /dev/null +++ b/app/facades/movie_facade.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +class MovieFacade + def initialize(endpoint) + @endpoint = endpoint + end + + def movies + results[:results] + end + + def movie + Movie.new(results) + end + + def cast + results[:cast].first(10) + end + + def reviews + results[:results] + end + + def image + results[:images] + end + + private + + def results + MovieService.new.get_url(@endpoint) + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index de6be7945..15b06f0f6 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module ApplicationHelper end diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb index d394c3d10..bef395997 100644 --- a/app/jobs/application_job.rb +++ b/app/jobs/application_job.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationJob < ActiveJob::Base # Automatically retry jobs that encountered a deadlock # retry_on ActiveRecord::Deadlocked diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index 3c34c8148..d84cb6e71 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -1,4 +1,6 @@ +# frozen_string_literal: true + class ApplicationMailer < ActionMailer::Base - default from: "from@example.com" - layout "mailer" + default from: 'from@example.com' + layout 'mailer' end diff --git a/app/models/application_record.rb b/app/models/application_record.rb index b63caeb8a..08dc53798 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationRecord < ActiveRecord::Base primary_abstract_class end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 000000000..2e1205392 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class User < ApplicationRecord + has_many :users_viewing_parties + has_many :viewing_parties, through: :users_viewing_parties + validates :name, presence: true + validates :email, presence: true, uniqueness: true +end diff --git a/app/models/users_viewing_party.rb b/app/models/users_viewing_party.rb new file mode 100644 index 000000000..9c4191c6e --- /dev/null +++ b/app/models/users_viewing_party.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class UsersViewingParty < ApplicationRecord + belongs_to :user + belongs_to :viewing_party + + def name + user.name + end +end diff --git a/app/models/viewing_party.rb b/app/models/viewing_party.rb new file mode 100644 index 000000000..eea879939 --- /dev/null +++ b/app/models/viewing_party.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class ViewingParty < ApplicationRecord + has_many :users_viewing_parties + has_many :users, through: :users_viewing_parties + validates :date, :start_time, :duration, :movie_id, presence: true + + def host + host = UsersViewingParty.where(viewing_party_id: id, hosting?: true).first + User.find(host.user_id).name + end + + def guests + users_viewing_parties.select do |uvp| + uvp.hosting? == false + end + end + + def start + "#{date.strftime('%A, %B %d, %Y')} #{start_time.strftime('%I:%M %P')}" + end + + def image_url + image = MovieFacade.new('3/configuration') + display = image.image + + "#{display[:base_url]}#{display[:backdrop_sizes][0]}#{movie_image}" + end +end diff --git a/app/poros/movie.rb b/app/poros/movie.rb new file mode 100644 index 000000000..1413a830b --- /dev/null +++ b/app/poros/movie.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +class Movie + @@movie = nil + attr_reader :id, + :title, + :img, + :vote_average, + :runtime, + :genres, + :summary + + def initialize(attributes) + @id = attributes[:id] + @title = attributes[:title] + @img = attributes[:poster_path] + @vote_average = attributes[:vote_average] + @runtime = attributes[:runtime] + @genres = attributes[:genres] + @summary = attributes[:overview] + @@movie = self + end + + def find_genres + @genres.map { |each| each[:name] }.join(', ') + end + + def find_runtime + hours = @runtime / 60 + mins = @runtime % 60 + "#{hours}h #{mins}mins" + end + + def self.movie + @@movie + end +end diff --git a/app/services/movie_service.rb b/app/services/movie_service.rb new file mode 100644 index 000000000..12760bcef --- /dev/null +++ b/app/services/movie_service.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +class MovieService + def conn + Faraday.new(url: 'https://api.themoviedb.org/') do |f| + f.params['api_key'] = Rails.application.credentials.themoviedb[:key] + end + end + + def get_url(url) + response = conn.get(url) + JSON.parse(response.body, symbolize_names: true) + end + + def search_movies(query) + get_url("3/search/movie?query=#{query}&include_adult=false&language=en-US&page=1") + end + + def top_rated_movies + get_url('3/movie/top_rated?language=en-US&page=1') + end + + def movie_details(movie_id) + get_url("3/movie/#{movie_id}?language=en-US") + end + + def cast(movie_id) + get_url("3/movie/#{movie_id}/credits?language=en-US") + end + + def movie_reviews(movie_id) + get_url("3/movie/#{movie_id}/reviews?language=en-US") + end +end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 552042a39..3f6d553e4 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -5,12 +5,18 @@ <%= csrf_meta_tags %> <%= csp_meta_tag %> - <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> <%= javascript_importmap_tags %>
+ <% flash.each do |type, msg| %> +