Skip to content

Commit

Permalink
Support api based migration of data between Quepid's (#834)
Browse files Browse the repository at this point in the history
After trying to get the existing api's to do migration, realized it was putting a square peg in round hole, so added new dedicated endpoints.
  • Loading branch information
epugh committed Sep 20, 2023
1 parent 720f5d6 commit 8896191
Show file tree
Hide file tree
Showing 55 changed files with 1,086 additions and 134 deletions.
36 changes: 34 additions & 2 deletions app/controllers/admin/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class UsersController < Admin::AdminController
# GET /admin/users.json
# GET /admin/users.csv
def index
@shallow = 'true' == params[:shallow]

@users = User.all

respond_to do |format|
Expand Down Expand Up @@ -42,8 +44,22 @@ def new
def edit; end

def create
@user = User.new user_params
params_to_use = user_params
if params[:password_encrypted].present?
params_to_use[:password] = 'blah'
params_to_use[:password_confirmation] = 'blah'
end

@user = User.new params_to_use

if @user.save
if params[:password_encrypted].present?
# avoid the encrypt call back
# rubocop:disable Rails/SkipsModelValidations
@user.update_column(:password, params[:password_encrypted])
# rubocop:enable Rails/SkipsModelValidations
end

redirect_to admin_user_path(@user)
else
render action: :new
Expand All @@ -52,9 +68,24 @@ def create

# PATCH/PUT /admin/users/1
# PATCH/PUT /admin/users/1.json
# rubocop:disable Metrics/MethodLength
def update
respond_to do |format|
if @user.update(user_params)
params_to_use = user_params

if params[:password_encrypted].present?
# avoid the encrypt call back
params_to_use[:password] = 'blah'
params_to_use[:password_confirmation] = 'blah'
end

if @user.update(params_to_use)
if params[:password_encrypted].present?
# avoid the encrypt call back
# rubocop:disable Rails/SkipsModelValidations
@user.update_column(:password, params[:password_encrypted])
# rubocop:enable Rails/SkipsModelValidations
end
Analytics::Tracker.track_user_updated_by_admin_event @user

format.html { redirect_to admin_user_path @user }
Expand All @@ -65,6 +96,7 @@ def update
end
end
end
# rubocop:enable Metrics/MethodLength

# DELETE /admin/users/1
# DELETE /admin/users/1.json
Expand Down
1 change: 1 addition & 0 deletions app/controllers/api/api_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class ApiController < ActionController::Base
include Authentication::CurrentCaseManager
include Authentication::CurrentQueryManager
include Authentication::CurrentTeamManager
include Authentication::CurrentBookManager
include NotificationsManager
include ApiKeyAuthenticatable

Expand Down
10 changes: 0 additions & 10 deletions app/controllers/api/v1/books/populate_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,6 @@ def update
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/MethodLength
# rubocop:enable Layout/LineLength

private

def find_book
@book = current_user.books_involved_with.where(id: params[:book_id]).first
end

def check_book
render json: { message: 'Book not found!' }, status: :not_found unless @book
end
end
end
end
Expand Down
10 changes: 0 additions & 10 deletions app/controllers/api/v1/books/refresh_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,6 @@ def update
respond_with @counts
end
# rubocop:enable Metrics/MethodLength

private

def find_book
@book = current_user.books_involved_with.where(id: params[:book_id]).first
end

def check_book
render json: { message: 'Book not found!' }, status: :not_found unless @book
end
end
end
end
Expand Down
44 changes: 42 additions & 2 deletions app/controllers/api/v1/books_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@
module Api
module V1
class BooksController < Api::ApiController
before_action :find_book, only: [ :show ]
before_action :check_book, only: [ :show ]
before_action :find_book, only: [ :show, :update, :destroy ]
before_action :check_book, only: [ :show, :update, :destroy ]

# rubocop:disable Metrics/MethodLength
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
def show
ActiveRecord::Type::Boolean.new
# @export = bool.deserialize params[:export] || false
@export = 'true' == params[:export]

respond_to do |format|
format.json
format.csv do
Expand Down Expand Up @@ -53,8 +57,44 @@ def show
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/PerceivedComplexity

def create
@book = Book.new(book_params)

if @book.save
# first = 1 == current_user.cases.count
# Analytics::Tracker.track_case_created_event current_user, @case, first
respond_with @book
else
render json: @book.errors, status: :bad_request
end
end

def update
update_params = book_params
if @book.update update_params
# Analytics::Tracker.track_case_updated_event current_user, @case
respond_with @book
else
render json: @book.errors, status: :bad_request
end
# rescue ActiveRecord::InvalidForeignKey
# render json: { error: 'Invalid id' }, status: :bad_request
end

def destroy
@book.destroy
# Analytics::Tracker.track_case_deleted_event current_user, @case

render json: {}, status: :no_content
end

private

def book_params
params.require(:book).permit(:team_id, :scorer_id, :selection_strategy_id, :name, :support_implicit_judgements,
:show_rank)
end

# rubocop:disable Layout/LineLength
def find_book
@book = current_user.books_involved_with.where(id: params[:id]).includes(:query_doc_pairs).preload([ query_doc_pairs: [ :judgements ] ]).first
Expand Down
16 changes: 16 additions & 0 deletions app/controllers/api/v1/export/books_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

module Api
module V1
module Export
class BooksController < Api::ApiController
before_action :find_book
before_action :check_book

def show
respond_with @book
end
end
end
end
end
16 changes: 16 additions & 0 deletions app/controllers/api/v1/export/cases_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

module Api
module V1
module Export
class CasesController < Api::ApiController
before_action :find_case
before_action :check_case

def show
respond_with @case
end
end
end
end
end
91 changes: 91 additions & 0 deletions app/controllers/api/v1/import/books_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# frozen_string_literal: true

module Api
module V1
module Import
class BooksController < Api::ApiController
# rubocop:disable Metrics/MethodLength
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
# rubocop:disable Layout/LineLength
def create
team_id = params.require(:team_id)
params_to_use = book_params.to_h.deep_symbolize_keys

@book = Book.new

@book.team = Team.find(team_id)

scorer_name = params_to_use[:scorer][:name]
unless Scorer.exists?(name: scorer_name)
@book.errors.add(:scorer, "Scorer with name '#{scorer_name}' needs to be migrated over first.")
end

selection_strategy_name = params_to_use[:selection_strategy][:name]
unless SelectionStrategy.exists?(name: selection_strategy_name)
@book.errors.add(:selection_strategy,
"Selection strategy with name '#{selection_strategy_name}' needs to be migrated over first.")
end

if params_to_use[:query_doc_pairs]
list_of_emails_of_users = []
params_to_use[:query_doc_pairs].each do |query_doc_pair|
next unless query_doc_pair[:judgements]

query_doc_pair[:judgements].each do |judgement|
list_of_emails_of_users << judgement[:user_email]
end
end
list_of_emails_of_users.uniq!
list_of_emails_of_users.each do |email|
unless User.exists?(email: email)
@book.errors.add(:base, "User with email '#{email}' needs to be migrated over first.")
end
end
end

unless @book.errors.empty?
render json: @book.errors, status: :bad_request
return
end

# passed first set of validations.
@book.name = params_to_use[:name]
@book.show_rank = params_to_use[:show_rank]
@book.support_implicit_judgements = params_to_use[:support_implicit_judgements]

@book.scorer = Scorer.find_by(name: scorer_name)
@book.selection_strategy = SelectionStrategy.find_by(name: selection_strategy_name)

params_to_use[:query_doc_pairs]&.each do |query_doc_pair|
qdp = @book.query_doc_pairs.build(query_doc_pair.except(:judgements))
next unless query_doc_pair[:judgements]

query_doc_pair[:judgements].each do |judgement|
judgement[:user] = User.find_by(email: judgement[:user_email])
qdp.judgements.build(judgement.except(:user_email))
end
end

if @book.save
respond_with @book
else
render json: @book.errors, status: :bad_request
end
end
# rubocop:enable Metrics/MethodLength
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/PerceivedComplexity
# rubocop:enable Layout/LineLength

private

def book_params
params.require(:book).permit!
end
end
end
end
end
94 changes: 94 additions & 0 deletions app/controllers/api/v1/import/cases_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# frozen_string_literal: true

module Api
module V1
module Import
class CasesController < Api::ApiController
# rubocop:disable Metrics/MethodLength
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
def create
list_of_emails_of_users = []
params_to_use = case_params.to_h.deep_symbolize_keys

@case = Case.new

list_of_emails_of_users << params_to_use[:owner_email]

scorer_name = params_to_use[:scorer][:name]
unless Scorer.exists?(name: scorer_name)
@case.errors.add(:scorer, "Scorer with name '#{scorer_name}' needs to be migrated over first.")
end

params_to_use[:queries]&.each do |query|
next unless query[:ratings]

query[:ratings].each do |rating|
list_of_emails_of_users << rating[:user_email] if rating[:user_email].present?
end
end

list_of_emails_of_users.uniq.each do |email|
unless User.exists?(email: email)
@case.errors.add(:base, "User with email '#{email}' needs to be migrated over first.")
end
end

unless @case.errors.empty?
render json: @case.errors, status: :bad_request
return
end

# passed first set of validations.
@case.case_name = params_to_use[:case_name]

@case.scorer = Scorer.find_by(name: scorer_name)

@case.owner = User.find_by(email: params_to_use[:owner_email])

# For some reason we can't do @case.queries.build with out forcing a save.
# Works fine with book however.
unless @case.save
render json: @case.errors, status: :bad_request
return
end

params_to_use[:queries]&.each do |query|
new_query = @case.queries.build(query.except(:ratings))
next unless query[:ratings]

query[:ratings].each do |rating|
rating[:user] = User.find_by(email: rating[:user_email]) if rating[:user_email].present?
new_query.ratings.build(rating.except(:user_email))
end
end

params_to_use[:try][:try_number] = 1

@case.tries.first.update(params_to_use[:try].except(:curator_variables))
params_to_use[:try][:curator_variables].each do |curator_variable|
# not sure why build and then the @case.save doesn't cascade down.
@case.tries.first.curator_variables.create curator_variable
end

if @case.save
respond_with @case
else
render json: @case.errors, status: :bad_request
end
end
# rubocop:enable Metrics/MethodLength
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/PerceivedComplexity

private

def case_params
params.require(:case).permit!
end
end
end
end
end
Loading

0 comments on commit 8896191

Please sign in to comment.