Skip to content

Commit

Permalink
Merge pull request #119 from curationexperts/importer
Browse files Browse the repository at this point in the history
Add an Item model and update import job
  • Loading branch information
mark-dce authored Nov 13, 2023
2 parents d97fc0a + 524b63b commit 0c79f13
Show file tree
Hide file tree
Showing 33 changed files with 703 additions and 16 deletions.
2 changes: 1 addition & 1 deletion app/controllers/admin/blueprints_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module Admin
# Manage user roles and authorizations
# Manage data model definitions
class BlueprintsController < ApplicationController
load_and_authorize_resource
before_action :check_for_empty_fields, only: :edit
Expand Down
74 changes: 74 additions & 0 deletions app/controllers/admin/items_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
module Admin
# Controller for UI to manage individual Items stored in the repository
class ItemsController < ApplicationController
before_action :set_item, only: %i[show edit update destroy]

# GET /items or /items.json
def index
@items = Item.all
end

# GET /items/1 or /items/1.json
def show; end

# GET /items/new
def new
blueprint_id = params['blueprint_id']
@item = Item.new(blueprint_id: blueprint_id)
@blueprint = Blueprint.find(blueprint_id) if blueprint_id
end

# GET /items/1/edit
def edit; end

# POST /items or /items.json
def create
@item = Item.new(item_params)

respond_to do |format|
if @item.save
format.html { redirect_to item_url(@item), notice: 'Item was successfully created.' }
format.json { render :show, status: :created, location: @item }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @item.errors, status: :unprocessable_entity }
end
end
end

# PATCH/PUT /items/1 or /items/1.json
def update
respond_to do |format|
if @item.update(item_params)
format.html { redirect_to item_url(@item), notice: 'Item was successfully updated.' }
format.json { render :show, status: :ok, location: @item }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: @item.errors, status: :unprocessable_entity }
end
end
end

# DELETE /items/1 or /items/1.json
def destroy
@item.destroy

respond_to do |format|
format.html { redirect_to items_url, notice: 'Item was successfully destroyed.' }
format.json { head :no_content }
end
end

private

# Use callbacks to share common setup or constraints between actions.
def set_item
@item = Item.find(params[:id])
end

# Only allow a list of trusted parameters through.
def item_params
params.require(:item).permit(:blueprint_id, description: {})
end
end
end
12 changes: 10 additions & 2 deletions app/jobs/import_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,15 @@ def perform(ingest)
end
end

def process_record(_doc)
sleep(1)
def process_record(doc)
blueprint_name = doc['has_model_ssim']&.first
blueprint = Blueprint.find_by(name: blueprint_name)
blueprint ||= Blueprint.find_by(name: 'Default') # TODO: remove when more blueprint functionality exists
d2 = {}
doc.each do |key, value|
new_key = blueprint.fields.find { |f| f.solr_field_name == key }&.display_label || key
d2[new_key] = value
end
Item.create(blueprint: blueprint, description: d2)
end
end
4 changes: 4 additions & 0 deletions app/models/field_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ class FieldConfig
attribute :search_results, :boolean, default: true
attribute :item_view, :boolean, default: true

# TODO: add data types
# see https://github.com/curationexperts/t3/blob/45a218ddae2a9637a0e387f9ae9dfb29329cdf6a/app/models/field.rb
# and JSON.parse(ActiveRecord::Type.registry.to_json)['registrations'].map{|r| r['name']}.compact.sort

def initialize(*)
super
self.display_label ||= suggested_label
Expand Down
36 changes: 36 additions & 0 deletions app/models/item.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Basic repository object, smallest unit of discovery
class Item < ApplicationRecord
belongs_to :blueprint

after_save :update_index

def to_partial_path
"admin/#{super}"
end

def update_index
save if changed?
document = to_solr
solr_connection.update params: {}, data: { add: { doc: document } }.to_json,
headers: { 'Content-Type' => 'application/json' }
solr_connection.update params: {}, data: { commit: {} }.to_json, headers: { 'Content-Type' => 'application/json' }
end

def to_solr
doc = []
doc << ['blueprint_ssi', blueprint.name]
doc << ['id', id]
blueprint.fields.each do |field|
label = field.solr_field_name
value = description[field.display_label]
doc << [label, value]
end
doc.to_h
end

private

def solr_connection
@solr_connection ||= CatalogController.blacklight_config.repository.connection
end
end
9 changes: 9 additions & 0 deletions app/views/admin/items/_choose_blueprint.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<h2>Choose a Blueprint</h2>
<div id='choose_blueprint'>
<% Blueprint.all.each do |blueprint| %>
<%= form_with(model: item) do |form| %>
<%= form.hidden_field :blueprint_id, value: blueprint.id %>
<%= form.submit blueprint.name %>
<% end %>
<% end %>
</div>
27 changes: 27 additions & 0 deletions app/views/admin/items/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<%= form_with(model: item, id: 'item_fields') do |form| %>
<% if item.errors.any? %>
<div style="color: red">
<h2><%= pluralize(item.errors.count, "error") %> prohibited this item from being saved:</h2>

<ul>
<% item.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>

<div>
<%= form.label :blueprint_id, style: "display: block" %>
<%= form.text_field :blueprint_id %>
</div>

<div>
<%= form.label :description, style: "display: block" %>
<%= form.text_field :description %>
</div>

<div>
<%= form.submit %>
</div>
<% end %>
12 changes: 12 additions & 0 deletions app/views/admin/items/_item.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<div id="<%= dom_id item %>">
<p>
<strong>Blueprint:</strong>
<%= item.blueprint_id %>
</p>

<p>
<strong>Description:</strong>
<%= item.description %>
</p>

</div>
2 changes: 2 additions & 0 deletions app/views/admin/items/_item.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
json.extract! item, :id, :blueprint_id, :description, :created_at, :updated_at
json.url item_url(item, format: :json)
10 changes: 10 additions & 0 deletions app/views/admin/items/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<h1>Editing item</h1>

<%= render "form", item: @item %>

<br>

<div>
<%= link_to "Show this item", @item %> |
<%= link_to "Back to items", items_path %>
</div>
14 changes: 14 additions & 0 deletions app/views/admin/items/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<p style="color: green"><%= notice %></p>

<h1>Items</h1>

<div id="items">
<% @items.each do |item| %>
<%= render item %>
<p>
<%= link_to "Show this item", item %>
</p>
<% end %>
</div>

<%= link_to "New item", new_item_path %>
1 change: 1 addition & 0 deletions app/views/admin/items/index.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
json.array! @items, partial: 'items/item', as: :item
13 changes: 13 additions & 0 deletions app/views/admin/items/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<h1>New item</h1>

<% if @blueprint %>
<%= render "form", item: @item, blueprint: @blueprint %>
<% else %>
<%= render "choose_blueprint", item: @item, blueprint: @blueprint %>
<% end %>

<br>

<div>
<%= link_to "Back to items", items_path %>
</div>
10 changes: 10 additions & 0 deletions app/views/admin/items/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<p style="color: green"><%= notice %></p>

<%= render @item %>

<div>
<%= link_to "Edit this item", edit_item_path(@item) %> |
<%= link_to "Back to items", items_path %>

<%= button_to "Destroy this item", @item, method: :delete %>
</div>
1 change: 1 addition & 0 deletions app/views/admin/items/show.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
json.partial! 'items/item', item: @item
4 changes: 4 additions & 0 deletions config/initializers/default_records.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
Role.create_with(description: 'Manages system configuration and defaults')
.find_or_create_by(name: 'System Manager')
end

if ActiveRecord::Base.connection.table_exists? 'blueprints'
Blueprint.create_with(fields: []).find_or_create_by(name: 'Default')
end
rescue ActiveRecord::NoDatabaseError
# database doesn't exist, don't try to do this yet
end
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
get :status, to: 'status#index'
post 'users/:id/password_reset', to: 'users#password_reset', as: :user_password_reset
resources :ingests
resources :items
resources :users
resources :roles
resources :blueprints
Expand Down
10 changes: 10 additions & 0 deletions db/migrate/20231108170540_create_items.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class CreateItems < ActiveRecord::Migration[7.0]
def change
create_table :items do |t|
t.references :blueprint, null: false, foreign_key: true
t.jsonb :description

t.timestamps
end
end
end
11 changes: 10 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion spec/factories/blueprints.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
FactoryBot.define do
factory :blueprint do
name { Faker::Hipster.words.join(' ').gsub(/[^0-9A-Za-z\-_ ]/, '') }
sequence(:name) { |n| "blank_blueprint_#{n}" }
end

factory :blueprint_with_basic_fields, class: 'Blueprint' do
sequence(:name) { |n| "basic_blueprint_#{n}" }
fields do
[
build(:field_config, display_label: 'title', solr_suffix: '*_tesi'),
build(:field_config, display_label: 'author', solr_suffix: '*_tesim'),
build(:field_config, display_label: 'date', solr_suffix: '*_isi')
]
end
end
end
4 changes: 2 additions & 2 deletions spec/factories/field_configs.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
FactoryBot.define do
factory :field_config do
display_label { Faker::Lorem.word.capitalize }
sequence(:display_label) { |n| "field_#{n}" }
solr_suffix { '*_tsi' }
solr_field_name { display_label.downcase + solr_suffix[1, 10] }
solr_field_name { display_label.downcase + solr_suffix.delete_prefix('*') }
enabled { true }
searchable { true }
facetable { true }
Expand Down
17 changes: 17 additions & 0 deletions spec/factories/items.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FactoryBot.define do
factory :item do
blueprint
description { '' }
end

factory :populated_item, class: 'Item' do
blueprint factory: %i[blueprint_with_basic_fields]
description do
{
'title' => 'One Hundred Years of Solitute',
'author' => 'Márquez, Gabriel García',
'date' => '1967'
}
end
end
end
Loading

0 comments on commit 0c79f13

Please sign in to comment.