diff --git a/.tool-versions b/.tool-versions index 6da6866f..64e71382 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ ruby 3.1.2 -postgres 14.4 +postgres 16.3 diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1c07694e..243be795 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,3 +1,8 @@ class ApplicationController < ActionController::Base protect_from_forgery with: :exception + before_action :authenticate_user! + + + private + end diff --git a/app/controllers/login_controller.rb b/app/controllers/login_controller.rb new file mode 100644 index 00000000..d81d8371 --- /dev/null +++ b/app/controllers/login_controller.rb @@ -0,0 +1,18 @@ +class LoginController < ApplicationController + + def create + Rails.logger.info("zzz") + if user = User.authenticate(params[:username], params[:password]) + Rails.logger.info(params) + # Save the user ID in the session so it can be used in + # subsequent requests + session[:current_user_id] = user.id + redirect_to root_url + end + end + + def delete + Rails.logger.info("zzz1") + session[:current_user_id] = nil + end +end diff --git a/app/controllers/news_controller.rb b/app/controllers/news_controller.rb new file mode 100644 index 00000000..56840cf2 --- /dev/null +++ b/app/controllers/news_controller.rb @@ -0,0 +1,37 @@ +class NewsController < ApplicationController + # before_action :require_login + helper_method :current_user + + def index + all_articles = Article.where(hn_time: 7.days.ago..).limit(100) + @articles = [] + @articles, @team_articles = all_articles.partition { |article| article.users.empty? } + @my_articles, @team_articles = @team_articles.partition { |article| article.users.pluck(:id).include?(current_user.id) } + # Cap this + @articles = @articles.slice(0, 50) + end + + def star + id = params["id"] + Rails.logger.info(id) + return unless id + return unless current_user + a = Article.find(id) + a.users << current_user + # a.save! + end + + def unstar + id = params["id"] + Rails.logger.info(id) + return unless id + return unless current_user + a = Article.find(id) + a.users.delete(current_user) + end + + #def current_user + # @current_user = User.first + # @current_user ||= User.find(session[:current_user_id]) if session[:current_user_id] + #end +end diff --git a/app/helpers/login_helper.rb b/app/helpers/login_helper.rb new file mode 100644 index 00000000..a0418e32 --- /dev/null +++ b/app/helpers/login_helper.rb @@ -0,0 +1,2 @@ +module LoginHelper +end diff --git a/app/helpers/news_helper.rb b/app/helpers/news_helper.rb new file mode 100644 index 00000000..9877c335 --- /dev/null +++ b/app/helpers/news_helper.rb @@ -0,0 +1,2 @@ +module NewsHelper +end diff --git a/app/models/article.rb b/app/models/article.rb new file mode 100644 index 00000000..19f1c84f --- /dev/null +++ b/app/models/article.rb @@ -0,0 +1,3 @@ +class Article < ApplicationRecord + has_and_belongs_to_many :users +end diff --git a/app/models/liked_article.rb b/app/models/liked_article.rb new file mode 100644 index 00000000..06575abe --- /dev/null +++ b/app/models/liked_article.rb @@ -0,0 +1,2 @@ +class LikedArticle < ApplicationRecord +end diff --git a/app/models/user.rb b/app/models/user.rb index b2091f9a..e2a6cb37 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,4 +3,11 @@ class User < ApplicationRecord # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable + + has_and_belongs_to_many :articles + + # def authenticate(email) + # User.find(email: email) + # end + end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 331a7ed0..3c77dd58 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -14,6 +14,25 @@

<%= alert %>

+

+ <% if current_user %> + <%= "Welcome " + current_user.email + " !" %> + <%= link_to 'Sign out', destroy_user_session_path, method: :delete %> + <% else %> + <%= link_to 'Sign in', new_user_session_path %> + + + <% end %> +

<%= yield %> diff --git a/app/views/news/index.html.erb b/app/views/news/index.html.erb new file mode 100644 index 00000000..26843d85 --- /dev/null +++ b/app/views/news/index.html.erb @@ -0,0 +1,34 @@ +

Welcome to Top News

+ +

Team Articles

+ + +

Trending Articles

+ + +

My Articles

+ \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index c12ef082..0b849f5c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,11 @@ Rails.application.routes.draw do devise_for :users - root to: 'pages#home' + #root to: 'pages#home' + + resources :logins, only: [:new, :create, :destroy] + + resources :news, only: [:get, :post] + post '/news/star', to: 'news#star' + post '/news/unstar', to: 'news#unstar' + root to: 'news#index' end diff --git a/db/migrate/20240718202257_create_articles.rb b/db/migrate/20240718202257_create_articles.rb new file mode 100644 index 00000000..83456f3c --- /dev/null +++ b/db/migrate/20240718202257_create_articles.rb @@ -0,0 +1,25 @@ +class CreateArticles < ActiveRecord::Migration[7.0] + def change + create_table :articles do |t| + t.integer :hn_id + t.string :title + t.string :author + t.datetime :hn_time + t.string :hn_url + t.string :hn_type + + t.timestamps + end + + create_table :articles_users, id: false do |t| + t.bigint :article_id + t.bigint :user_id + + t.timestamps + end + + add_index :articles_users, :article_id + add_index :articles_users, :user_id + end + +end diff --git a/db/migrate/20240718233906_add_article_indices.rb b/db/migrate/20240718233906_add_article_indices.rb new file mode 100644 index 00000000..ea7a382e --- /dev/null +++ b/db/migrate/20240718233906_add_article_indices.rb @@ -0,0 +1,6 @@ +class AddArticleIndices < ActiveRecord::Migration[7.0] + def change + add_index :articles, :hn_id, unique: true + add_index :articles, :hn_time + end +end diff --git a/db/schema.rb b/db/schema.rb index acc34f3b..e0077f53 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,10 +10,32 @@ # # 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_18_233906) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" + create_table "articles", force: :cascade do |t| + t.integer "hn_id" + t.string "title" + t.string "author" + t.datetime "hn_time" + t.string "hn_url" + t.string "hn_type" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["hn_id"], name: "index_articles_on_hn_id", unique: true + t.index ["hn_time"], name: "index_articles_on_hn_time" + end + + create_table "articles_users", id: false, force: :cascade do |t| + t.bigint "article_id" + t.bigint "user_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["article_id"], name: "index_articles_users_on_article_id" + t.index ["user_id"], name: "index_articles_users_on_user_id" + end + create_table "users", force: :cascade do |t| t.string "first_name" t.string "last_name" diff --git a/lib/tasks/refresh_articles.rake b/lib/tasks/refresh_articles.rake new file mode 100644 index 00000000..a44c1b62 --- /dev/null +++ b/lib/tasks/refresh_articles.rake @@ -0,0 +1,31 @@ +namespace :refresh_articles do + + HN_TOP_STORIES_URL = "https://hacker-news.firebaseio.com/v0/topstories.json" + + desc "Populate" + task fetch: :environment do + # TODO: Use something fancier like Faraday + resp = Net::HTTP.get_response(URI.parse(HN_TOP_STORIES_URL)) + body = resp.body + stories = JSON.parse(body) + stories.each { |id| + next if Article.where(hn_id: id).any? + story_url = "https://hacker-news.firebaseio.com/v0/item/#{id}.json" + resp = Net::HTTP.get_response(URI.parse(story_url)) + body = resp.body + details = JSON.parse(body) + a = Article.new(hn_id: id, title: details["title"], author: details["author"], + hn_time: Time.at(details["time"]), hn_url: details["url"], hn_type: details["story"]) + a.save! + } + + end + + desc "Delete old articles" + task erase: :environment do + # TODO: Make this configurable + Article.where(hn_time: ..7.days.ago).delete_all + # TODO: Save starred articles? + end + +end diff --git a/spec/helpers/login_helper_spec.rb b/spec/helpers/login_helper_spec.rb new file mode 100644 index 00000000..519f5626 --- /dev/null +++ b/spec/helpers/login_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the LoginHelper. For example: +# +# describe LoginHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe LoginHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/helpers/news_helper_spec.rb b/spec/helpers/news_helper_spec.rb new file mode 100644 index 00000000..c335c7d1 --- /dev/null +++ b/spec/helpers/news_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the NewsHelper. For example: +# +# describe NewsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe NewsHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/article_spec.rb b/spec/models/article_spec.rb new file mode 100644 index 00000000..632e8564 --- /dev/null +++ b/spec/models/article_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Article, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/liked_article_spec.rb b/spec/models/liked_article_spec.rb new file mode 100644 index 00000000..8d24bc1b --- /dev/null +++ b/spec/models/liked_article_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe LikedArticle, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/login_spec.rb b/spec/requests/login_spec.rb new file mode 100644 index 00000000..c6268d61 --- /dev/null +++ b/spec/requests/login_spec.rb @@ -0,0 +1,7 @@ +require 'rails_helper' + +RSpec.describe "Logins", type: :request do + describe "GET /index" do + pending "add some examples (or delete) #{__FILE__}" + end +end diff --git a/spec/requests/news_spec.rb b/spec/requests/news_spec.rb new file mode 100644 index 00000000..3e741eb6 --- /dev/null +++ b/spec/requests/news_spec.rb @@ -0,0 +1,7 @@ +require 'rails_helper' + +RSpec.describe "News", type: :request do + describe "GET /index" do + pending "add some examples (or delete) #{__FILE__}" + end +end