Skip to content

Commit

Permalink
Reviews Endpoint Initial Scaffold (#296)
Browse files Browse the repository at this point in the history
  • Loading branch information
talha-ahsan authored Jul 29, 2024
1 parent ced9841 commit 8ba4dec
Show file tree
Hide file tree
Showing 25 changed files with 420 additions and 1 deletion.
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ gem 'opentelemetry-sdk'
gem 'opentelemetry-exporter-otlp'
gem 'opentelemetry-instrumentation-all'

# for review imports from NRDBc
gem 'reverse_markdown'

group :development, :test do
gem "brakeman", "~> 5.2"
gem "bundler-audit", "~> 0.9.0"
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,8 @@ GEM
responders (3.1.1)
actionpack (>= 5.2)
railties (>= 5.2)
reverse_markdown (2.1.1)
nokogiri
rexml (3.3.2)
strscan
rspec (3.12.0)
Expand Down Expand Up @@ -572,6 +574,7 @@ DEPENDENCIES
rack-cors (= 2.0.0)
rails (>= 7.0.7.1)
responders
reverse_markdown
rspec-rails
rspec_api_documentation
rubocop
Expand Down
14 changes: 14 additions & 0 deletions app/controllers/reviews_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

# Controller for the Review resource.
class ReviewsController < ApplicationController
def index
reviews = ReviewResource.all(params)
respond_with(reviews)
end

def show
reviews = ReviewResource.find(params)
respond_with(reviews)
end
end
1 change: 1 addition & 0 deletions app/models/card.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def restrictions
class_name: 'RawPrinting',
primary_key: :id

has_many :reviews
has_many :printings,
primary_key: :id

Expand Down
13 changes: 13 additions & 0 deletions app/models/review.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class Review < ApplicationRecord
belongs_to :card
has_many :review_comments
has_many :review_votes

def votes
review_votes.count
end

def comments
review_comments
end
end
3 changes: 3 additions & 0 deletions app/models/review_comment.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class ReviewComment < ApplicationRecord
belongs_to :review
end
3 changes: 3 additions & 0 deletions app/models/review_vote.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class ReviewVote < ApplicationRecord
belongs_to :review
end
1 change: 1 addition & 0 deletions app/resources/card_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ class CardResource < ApplicationResource # rubocop:disable Metrics/ClassLength
end
end
has_many :rulings
has_many :reviews
belongs_to :side

many_to_many :decklists do
Expand Down
33 changes: 33 additions & 0 deletions app/resources/review_resource.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

# Resource for the Review object (currently imported from NRDBc)
class ReviewResource < ApplicationResource
primary_endpoint '/reviews', %i[index show]

attribute :id, :integer
attribute :username, :string do
@object.user_id
end
attribute :body, :string
attribute :card, :string do
@object.card.title
end
attribute :card_id, :string
attribute :created_at, :datetime
attribute :updated_at, :datetime
attribute :votes, :integer

belongs_to :card

attribute :comments, :array do
@object.comments.map do |comment|
{
id: comment.id,
body: comment.body,
user: comment.user_id,
created_at: comment.created_at,
updated_at: comment.updated_at
}
end
end
end
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
resources :illustrators, only: %i[index show]
resources :printings, only: %i[index show]
resources :restrictions, only: %i[index show]
resources :reviews, only: %i[index show]
resources :rulings, only: %i[index show]
resources :sides, only: %i[index show]
resources :snapshots, only: %i[index show]
Expand Down
13 changes: 13 additions & 0 deletions db/migrate/20240712003906_create_reviews.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class CreateReviews < ActiveRecord::Migration[7.1]
def change
create_table :reviews do |t|
t.text :ruling
t.string :username
t.text :card_id, null: false

t.timestamps
end

add_foreign_key :reviews, :cards
end
end
11 changes: 11 additions & 0 deletions db/migrate/20240712005347_create_review_comments.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class CreateReviewComments < ActiveRecord::Migration[7.1]
def change
create_table :review_comments do |t|
t.text :body
t.string :username
t.references :review, null: false, foreign_key: true

t.timestamps
end
end
end
10 changes: 10 additions & 0 deletions db/migrate/20240712005953_create_review_votes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class CreateReviewVotes < ActiveRecord::Migration[7.1]
def change
create_table :review_votes do |t|
t.string :username
t.references :review, null: false, foreign_key: true

t.timestamps
end
end
end
7 changes: 7 additions & 0 deletions db/migrate/20240716062705_rename_review_ruling_to_body.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class RenameReviewRulingToBody < ActiveRecord::Migration[7.1]
def change
change_table :reviews do |t|
t.rename :ruling, :body
end
end
end
18 changes: 18 additions & 0 deletions db/migrate/20240721065003_rename_review_username_to_user_id.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class RenameReviewUsernameToUserId < ActiveRecord::Migration[7.1]
def change
change_table :reviews do |t|
t.remove :username
end
add_reference :reviews, :user, type: :string

change_table :review_comments do |t|
t.remove :username
end
add_reference :review_comments, :user, type: :string

change_table :review_votes do |t|
# temporary, actual usernames not available yet, using placeholder values instead
t.rename :username, :user_id
end
end
end
32 changes: 31 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.1].define(version: 2024_06_22_192959) do
ActiveRecord::Schema[7.1].define(version: 2024_07_21_065003) do
# These are extensions that must be enabled in order to support this database
enable_extension "pgcrypto"
enable_extension "plpgsql"
Expand Down Expand Up @@ -281,6 +281,33 @@
t.datetime "updated_at", null: false
end

create_table "review_comments", force: :cascade do |t|
t.text "body"
t.bigint "review_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "user_id"
t.index ["review_id"], name: "index_review_comments_on_review_id"
t.index ["user_id"], name: "index_review_comments_on_user_id"
end

create_table "review_votes", force: :cascade do |t|
t.string "user_id"
t.bigint "review_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["review_id"], name: "index_review_votes_on_review_id"
end

create_table "reviews", force: :cascade do |t|
t.text "body"
t.text "card_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "user_id"
t.index ["user_id"], name: "index_reviews_on_user_id"
end

create_table "rulings", force: :cascade do |t|
t.string "card_id", null: false
t.string "question"
Expand Down Expand Up @@ -352,6 +379,9 @@
add_foreign_key "restrictions_cards_restricted", "restrictions"
add_foreign_key "restrictions_cards_universal_faction_cost", "cards"
add_foreign_key "restrictions_cards_universal_faction_cost", "restrictions"
add_foreign_key "review_comments", "reviews"
add_foreign_key "review_votes", "reviews"
add_foreign_key "reviews", "cards"
add_foreign_key "rulings", "cards"
add_foreign_key "snapshots", "card_pools"
add_foreign_key "snapshots", "formats"
Expand Down
97 changes: 97 additions & 0 deletions lib/tasks/reviews.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# frozen_string_literal: true

require 'json'
require 'net/http'
require 'optparse'
require 'uri'
require 'reverse_markdown'
namespace :reviews do
desc 'Imports review from NRDBc, currently storing usernames as strings instead of references'

def text_to_id(text)
text.downcase
.unicode_normalize(:nfd)
.gsub(/\P{ASCII}/, '')
.gsub(/'s(\p{Space}|\z)/, 's\1')
.split(/[\p{Space}\p{Punct}]+/)
.reject { |s| s&.strip&.empty? }
.join('_')
end

def retrieve_reviews
url = URI('https://netrunnerdb.com/api/2.0/public/reviews')

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)

response = http.request(request)

return JSON.parse(response.body) if response.is_a?(Net::HTTPSuccess)

raise "Failed to retrieve reviews! Status code: #{response.code}"
end

def purge_tables
# Only do this in a transaction
raise 'Called DB purge outside of a transaction!' unless Review.connection.transaction_open?

puts 'Purging Review Tables'
ReviewVote.delete_all
ReviewComment.delete_all
Review.delete_all
end

task import: :environment do
puts 'Importing Reviews from NetrunnerDB Classic'
reviews_body = retrieve_reviews

card_ids = Card.all.pluck(:id).to_set
Review.transaction do
purge_tables
puts 'Starting import'
reviews_body['data'].each do |review|
card_name = review['title']
rev_body = ReverseMarkdown.convert review['ruling']
username = review['user']
comments = review['comments']

card_id = text_to_id(card_name)
if card_ids.include? card_id
r = Review.new
r.card_id = card_id
r.user_id = username
r.body = rev_body
r.created_at = DateTime.parse(review['date_create'])
r.updated_at = DateTime.parse(review['date_update'])
r.save!

# Hack for votes: generate filler entries in the join table
ReviewVote.transaction do
review['votes'].times do
vote = ReviewVote.new
vote.user_id = 'TBD_Future_Problem'
vote.review = r
vote.save!
end
end

# Generate Comments for each deck
ReviewComment.transaction do
comments.each do |comment|
c = ReviewComment.new
c.user_id = comment['user']
c.body = ReverseMarkdown.convert comment['comment']
c.review = r
c.created_at = comment['date_create']
c.updated_at = comment['date_update']
c.save!
end
end
else
puts "Missing Card entry with title: #{card_name}"
end
end
end
end
end
1 change: 1 addition & 0 deletions spec/acceptance/cards_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* Decklists
* Faction
* Printings
* Reviews
* Rulings
* Side
EXPLANATION
Expand Down
39 changes: 39 additions & 0 deletions spec/acceptance/reviews_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true

require 'rails_helper'
require 'rspec_api_documentation/dsl'

resource 'Reviews' do
header 'Content-Type', 'application/json'
header 'Host', 'api-preview.netrunnderdb.com'

explanation <<~EXPLANATION
Card reviews have the following relationships
* Card
EXPLANATION

get '/api/v3/public/reviews' do
example_request 'All Reviews' do
expect(status).to eq 200
end
end

get '/api/v3/public/reviews/:id' do
parameter :id, type: :string, required: true

let(:id) { '1' }
example_request 'Get A Single Review' do
expect(status).to eq 200
end
end

get '/api/v3/public/reviews?filter[card_id]=:query' do
parameter :query, type: :string, required: true

let(:query) { 'endurance' }
example_request 'Filter on a single card id' do
expect(status).to eq 200
end
end
end
Loading

0 comments on commit 8ba4dec

Please sign in to comment.