Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,28 @@ source 'https://rubygems.org'

ruby File.read('.ruby-version').chomp

gem 'byebug', platforms: [:mri, :mingw, :x64_mingw], group: [:development, :test]
gem 'capybara', group: [:development, :test]
gem 'coffee-rails'
gem 'devise'
gem 'jbuilder'
gem 'listen', group: :development
gem 'pg'
gem 'pry-rails'
gem 'puma'
gem 'rails', '~> 7.0.3'
gem 'rspec-rails'
gem 'sass-rails'
gem 'selenium-webdriver', group: [:development, :test]
gem 'spring', group: :development
gem 'turbolinks'
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
gem 'uglifier'
gem 'web-console', group: :development
gem 'faraday'

group :development, :test do
gem 'rspec-rails'
gem 'selenium-webdriver'
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
gem 'capybara'
end

group :development do
gem 'spring'
gem 'web-console'
gem 'listen'
end
76 changes: 76 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ GEM
tzinfo (~> 2.0)
addressable (2.8.1)
public_suffix (>= 2.0.2, < 6.0)
base64 (0.2.0)
bcrypt (3.1.18)
bigdecimal (3.1.8)
bindex (0.8.1)
builder (3.2.4)
byebug (11.1.3)
Expand Down Expand Up @@ -102,17 +104,77 @@ GEM
digest (3.1.0)
erubi (1.11.0)
execjs (2.8.1)
faraday (2.10.0)
faraday-net_http (>= 2.0, < 3.2)
logger
faraday-net_http (3.1.0)
net-http
faraday-retry (2.2.1)
faraday (~> 2.0)
ffi (1.15.5)
gapic-common (0.22.0)
faraday (>= 1.9, < 3.a)
faraday-retry (>= 1.0, < 3.a)
google-protobuf (>= 3.25, < 5.a)
googleapis-common-protos (~> 1.6)
googleapis-common-protos-types (~> 1.15)
googleauth (~> 1.11)
grpc (~> 1.65)
globalid (1.0.0)
activesupport (>= 5.0)
google-cloud-core (1.7.0)
google-cloud-env (>= 1.0, < 3.a)
google-cloud-errors (~> 1.0)
google-cloud-env (2.1.1)
faraday (>= 1.0, < 3.a)
google-cloud-errors (1.4.0)
google-cloud-firestore (2.16.0)
bigdecimal (~> 3.0)
concurrent-ruby (~> 1.0)
google-cloud-core (~> 1.5)
google-cloud-firestore-v1 (>= 0.10, < 2.a)
rbtree (~> 0.4.2)
google-cloud-firestore-v1 (1.0.0)
gapic-common (>= 0.21.1, < 2.a)
google-cloud-errors (~> 1.0)
google-cloud-location (>= 0.7, < 2.a)
google-cloud-location (0.8.0)
gapic-common (>= 0.21.1, < 2.a)
google-cloud-errors (~> 1.0)
google-protobuf (4.27.2)
bigdecimal
rake (>= 13)
googleapis-common-protos (1.6.0)
google-protobuf (>= 3.18, < 5.a)
googleapis-common-protos-types (~> 1.7)
grpc (~> 1.41)
googleapis-common-protos-types (1.15.0)
google-protobuf (>= 3.18, < 5.a)
googleauth (1.11.0)
faraday (>= 1.0, < 3.a)
google-cloud-env (~> 2.1)
jwt (>= 1.4, < 3.0)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
grpc (1.65.1)
google-protobuf (>= 3.25, < 5.0)
googleapis-common-protos-types (~> 1.0)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
jbuilder (2.11.5)
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
jwt (2.8.2)
base64
launchy (2.5.2)
addressable (~> 2.8)
letter_opener (1.10.0)
launchy (>= 2.2, < 4)
listen (3.7.1)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
logger (1.6.0)
loofah (2.19.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
Expand All @@ -124,6 +186,9 @@ GEM
mini_mime (1.1.2)
mini_portile2 (2.8.0)
minitest (5.16.3)
multi_json (1.15.0)
net-http (0.4.1)
uri
net-imap (0.2.3)
digest
net-protocol
Expand All @@ -143,6 +208,7 @@ GEM
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
orm_adapter (0.5.0)
os (1.1.4)
pg (1.4.3)
pry (0.14.1)
coderay (~> 1.1)
Expand Down Expand Up @@ -186,6 +252,7 @@ GEM
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
rbtree (0.4.6)
regexp_parser (2.5.0)
responders (3.0.1)
actionpack (>= 5.0)
Expand Down Expand Up @@ -224,6 +291,11 @@ GEM
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
signet (0.19.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
spring (4.1.0)
sprockets (4.1.1)
concurrent-ruby (~> 1.0)
Expand All @@ -243,6 +315,7 @@ GEM
concurrent-ruby (~> 1.0)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
uri (0.13.0)
warden (1.2.9)
rack (>= 2.0.9)
web-console (4.2.0)
Expand All @@ -266,7 +339,10 @@ DEPENDENCIES
capybara
coffee-rails
devise
faraday
google-cloud-firestore
jbuilder
letter_opener
listen
pg
pry-rails
Expand Down
13 changes: 13 additions & 0 deletions app/controllers/news_items_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class NewsItemsController < ApplicationController
def index
@news_items = NewsItem.all
end

def create
@news_item = NewsItem.find_or_initialize_by(hacker_news_id: params[:hacker_news_id], title: params[:title], url: params[:url], item_type: params[:type])
@news_item.favorites.build(user_id: current_user.id)
if @news_item.save
redirect_to news_items_url
end
end
end
6 changes: 6 additions & 0 deletions app/controllers/pages_controller.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
class PagesController < ApplicationController

def home
news_service = ApiClient.new

@hacker_news_items = news_service.top_stories
end
end
4 changes: 4 additions & 0 deletions app/models/favorite.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class Favorite < ApplicationRecord
belongs_to :user
belongs_to :news_item
end
5 changes: 5 additions & 0 deletions app/models/news_item.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class NewsItem < ApplicationRecord

has_many :favorites
has_many :users, through: :favorites
end
4 changes: 4 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ class User < ApplicationRecord
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable


has_many :favorites
has_many :news_items, through: :favorites
end
33 changes: 33 additions & 0 deletions app/services/api_client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
class ApiClient
BASE_URL = "https://hacker-news.firebaseio.com"

def initialize
@connection = Faraday.new(url: BASE_URL) do |faraday|
faraday.response :logger
faraday.adapter Faraday.default_adapter
faraday.headers[''] = ''
end
end

def top_item_ids
response = @connection.get '/v0/topstories.json'
JSON.parse response.body
end

def top_stories(limit=30)
top_item_ids[0..limit].map{|item_id| get_story(item_id)}.compact
end

def get_story(story_id)
response = @connection.get "/v0/item/#{story_id}.json"
Struct.new("Item", :hacker_news_id, :url, :title, :type, :liked)

parsed_response = JSON.parse response.body

if parsed_response
Struct::Item.new(parsed_response['id'], parsed_response['url'], parsed_response['title'], parsed_response['type'], false)
end

end

end
7 changes: 7 additions & 0 deletions app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
<p class="alert">
<%= alert %>
</p>
<%= link_to "Home", root_path %>
<% if user_signed_in? -%>
<%= link_to "Team Likes", news_items_path %>
<%= link_to "sign out", destroy_user_session_path, :method => :delete %>
<% else -%>
<%= link_to "sign in", "/users/sign_in" %>
<% end -%>
<%= yield %>
</body>
</html>
15 changes: 15 additions & 0 deletions app/views/news_items/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<h1>Team Favorites</h1>
<ul>
<% @news_items.each do |news_item| %>
<li> <%= news_item.title %>
<p>
<% news_item.users.map(&:email).each_with_index do |email,ind| %>
<span>
<% if ind > 0 %>, <% end %>
<%= email %>
</span>
<% end%>
</p>
</li></span>
<% end %>
</ul>
13 changes: 13 additions & 0 deletions app/views/pages/home.html.erb
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
<h1>Welcome to Top News</h1>
<ul>
<% @hacker_news_items.each do |news_item| %>
<li><%= news_item['title'] %>
<% if user_signed_in? %>
<% if current_user.news_items.map(&:hacker_news_id).include? news_item.hacker_news_id %>
<p>Liked</p>
<% else %>
<%= button_to "Like", news_items_path, params: { hacker_news_id: news_item.hacker_news_id, title: news_item.title, url: news_item.url, type: news_item.type, liked: false } %>
<% end %>
<% end %>
</li>
<% end %>
</ul>
4 changes: 3 additions & 1 deletion config/environments/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# 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
config.cache_classes = false

# 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
Expand Down Expand Up @@ -37,6 +37,8 @@
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr

config.active_record.legacy_connection_handling = false

# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
end
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Rails.application.routes.draw do
resources :news_items, only: [:index, :create]
devise_for :users
root to: 'pages#home'
end
14 changes: 14 additions & 0 deletions db/migrate/20240724092828_create_news_items.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class CreateNewsItems < ActiveRecord::Migration[7.0]
def change
create_table :news_items do |t|
t.string :title
t.string :item_type
t.string :url
t.integer :hacker_news_id

t.timestamps

t.index :hacker_news_id
end
end
end
10 changes: 10 additions & 0 deletions db/migrate/20240724095033_create_favorites.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class CreateFavorites < ActiveRecord::Migration[7.0]
def change
create_table :favorites do |t|
t.integer :user_id
t.integer :news_item_id

t.timestamps
end
end
end
19 changes: 18 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,27 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.0].define(version: 2018_02_28_212101) do
ActiveRecord::Schema[7.0].define(version: 2024_07_24_095033) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

create_table "favorites", force: :cascade do |t|
t.integer "user_id"
t.integer "news_item_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

create_table "news_items", force: :cascade do |t|
t.string "title"
t.string "item_type"
t.string "url"
t.integer "hacker_news_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["hacker_news_id"], name: "index_news_items_on_hacker_news_id"
end

create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
Expand Down
14 changes: 14 additions & 0 deletions spec/models/news_item_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require 'rails_helper'

RSpec.describe NewsItem, type: :model do

context "creating a new news_item" do
let(:attrs) do
{ hacker_news_id: 322222, url: 'url_for_news', title: 'TestTitle', item_type: 'article' }
end

it "should have hacker_news_id, url, title, and item_type" do
expect { NewsItem.create(attrs) }.to change{ NewsItem.count }.by(1)
end
end
end