Skip to content

Commit

Permalink
implemented uncollected_works_collection
Browse files Browse the repository at this point in the history
  • Loading branch information
damisul committed Jul 24, 2024
1 parent 24b85f9 commit 324e7fc
Show file tree
Hide file tree
Showing 18 changed files with 283 additions and 20 deletions.
21 changes: 21 additions & 0 deletions app/controllers/admin/authorities_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

module Admin
# Controller to work with Authorities records
class AuthoritiesController < ApplicationController
before_action :require_editor

before_action :set_authority, only: %i(refresh_uncollected_works_collection)

def refresh_uncollected_works_collection
RefreshUncollectedWorksCollection.call(@authority)
redirect_to authority_path(@authority), notice: t(:updated_successfully)
end

private

def set_authority
@authority = Authority.find(params[:id])
end
end
end
2 changes: 1 addition & 1 deletion app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ def prep_user_content(context = :manifestation)
end

def prep_toc_as_collection
@root_collection = @author.root_collection
@root_collection = @author.obtain_root_collection
@toc = @author.toc # may be nil
# credits = @author.toc.credit_section || ''
# credits.sub!(
Expand Down
23 changes: 18 additions & 5 deletions app/models/authority.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class Authority < ApplicationRecord

belongs_to :person, optional: true
belongs_to :corporate_body, optional: true
belongs_to :root_collection, class_name: 'Collection', optional: true
belongs_to :uncollected_works_collection, class_name: 'Collection', optional: true

attr_readonly :person, :corporate_body # Should not be modified after creation

Expand Down Expand Up @@ -74,6 +76,8 @@ class Authority < ApplicationRecord
# validations
validates :name, :intellectual_property, presence: true
validates :wikidata_uri, format: WIKIDATA_URI_PATTERN, allow_nil: true
validates :uncollected_works_collection, uniqueness: true, allow_nil: true
validate :validate_collection_types
validate :validate_linked_authority

validates_attachment_content_type :profile_image, content_type: %r{\Aimage/.*\z}
Expand Down Expand Up @@ -334,11 +338,8 @@ def publish_if_first!
publish! if awaiting_first?
end

def root_collection
return @root_collection if @root_collection
return @root_collection = Collection.find(root_collection_id) if root_collection_id

return @root_collection = generate_root_collection!
def obtain_root_collection
self.root_collection ||= generate_root_collection!
end

def generate_root_collection!
Expand Down Expand Up @@ -401,4 +402,16 @@ def validate_linked_authority
errors.add(:base, :no_linked_authority) if person.nil? && corporate_body.nil?
errors.add(:base, :multiple_linked_authorities) if person.present? && corporate_body.present?
end

# rubocop:disable Style/GuardClause
def validate_collection_types
if root_collection.present? && !root_collection.root?
errors.add(:root_collection, :wrong_collection_type, expected_type: :root)
end

if uncollected_works_collection.present? && !uncollected_works_collection.uncollected?
errors.add(:uncollected_works_collection, :wrong_collection_type, expected_type: :uncollected)
end
end
# rubocop:enable Style/GuardClause
end
11 changes: 10 additions & 1 deletion app/models/collection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,16 @@ class Collection < ApplicationRecord
# a multi-volume work, are their appropriate type -- a manifestation if a single text, a collection of type volume
# if a book, etc.;
# other is a catch-all for anything else
enum collection_type: { volume: 0, periodical: 1, periodical_issue: 2, series: 3, root: 4, other: 5 }
# uncollected is used to group authority's works not belonging to any other collections. Each authority can have one.
enum collection_type: {
volume: 0,
periodical: 1,
periodical_issue: 2,
series: 3,
root: 4,
other: 5,
uncollected: 100
}
enum toc_strategy: { default: 0, custom_markdown: 1 } # placeholder for future custom ToC-generation strategies

# scope :published, -> { where(status: Collection.statuses[:published]) }
Expand Down
58 changes: 58 additions & 0 deletions app/services/refresh_uncollected_works_collection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# frozen_string_literal: true

# We want to group all works author was involved into but not belonging to any colleciton into a special
# 'Uncollected works' collection
class RefreshUncollectedWorksCollection < ApplicationService
# rubocop:disable Style/GuardClause
def call(authority)
collection = authority.uncollected_works_collection

remove_collected_works(authority) if collection.present?

if collection.nil?
collection = Collection.new(
collection_type: :uncollected,
title: I18n.t(:uncollected_works_collection_title)
)
end

nextseqno = (collection.collection_items.maximum(:seqno) || 0) + 1

# Checking all manifestations given authority is involved into as author or translator
authority.manifestations(:author, :translator)
.preload(collection_items: :collection)
.find_each do |m|
# skipping if manifestation is included in some other collection or already included in uncollected works
# collection for this authority
next if m.collection_items.any? do |ci|
!ci.collection.uncollected? || (collection.present? && ci.collection == collection)
end

collection.collection_items.build(item: m, seqno: nextseqno)
nextseqno += 1
end

collection.save! # should save all added items

if authority.uncollected_works_collection.nil?
authority.uncollected_works_collection = collection
authority.save!
end
end
# rubocop:enable Style/GuardClause

# removes from uncollected_works collection works which was included in some other collection
def remove_collected_works(authority)
authority.uncollected_works_collection
.collection_items
.preload(item: { collection_items: :collection })
.find_each do |collection_item|
# The only possible item type in uncollected works collection is Manifestation
manifestation = collection_item.item
# NOTE: same work can be in several different uncollected works collection related to different authorities
if manifestation.collection_items.any? { |ci| !ci.collection.uncollected? }
collection_item.destroy!
end
end
end
end
8 changes: 7 additions & 1 deletion app/views/authors/toc.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,13 @@
!= "&nbsp;&nbsp;&nbsp;"
%span.static-btn
%b= link_to t(:edit_metadata), authors_edit_path(id: @author.id)


!= '&nbsp;&nbsp;&nbsp;'
%span.static-btn
%b= link_to 'Refresh uncollected works',
refresh_uncollected_works_collection_admin_authority_path(@author),
method: :post

.select-all-with-buttons{style:'display:none;margin-right:100px;'}
.number-of-selected-texts{style: 'display:none'}
= t(:number_of_selected_texts)
Expand Down
2 changes: 1 addition & 1 deletion app/views/shared/_collection.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@
- else
.headline-3-v02
= t(:text)
:
\:
= link_to collection_item_string(ci), default_link_by_class(ci.item.class, ci.item.id)
1 change: 1 addition & 0 deletions config/locales/active_record.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ en:
base:
no_linked_authority: either Person or CorporateBody object must be specified
multiple_linked_authorities: Person and CorporateBody objects cannot be specified together
wrong_collection_type: must be of '%{expected_type}' type
attributes:
authority:
other_designation: Other designation
Expand Down
1 change: 1 addition & 0 deletions config/locales/active_record.he.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ he:
base:
no_linked_authority: יש לקשר או רשומת אישים או רשומת ארגונים
multiple_linked_authorities: אי אפשר לקשר גם רשומת אישים וגם רשומת ארגונים
wrong_collection_type: must be of '%{expected_type}' type
attributes:
authority:
other_designation: כינויים אחרים
Expand Down
2 changes: 2 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ en:
feature_on: Featuring Periods
unknown: Unknown
sort_by: Sort by
uncollected_works_collection_title: Uncollected works

admin:
featured_contents:
index:
Expand Down
1 change: 1 addition & 0 deletions config/locales/he.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,7 @@ he:
ctype_series_up_link: לתצוגת המחזור/שער כולו
parent_collections: "שייך לאוספים:"
collection_circular_reference: אוסף מקושר לעצמו!
uncollected_works_collection_title: Uncollected works

notifications:
proof_fixed:
Expand Down
6 changes: 6 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
resources :features, controller: 'featured_content_features', only: %i(create)
end
resources :featured_content_features, only: %i(destroy)

resources :authorities, only: [] do
member do
post :refresh_uncollected_works_collection
end
end
end

resources :ingestibles do
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

class AddUncollectedWorksCollectionIdToAuthorities < ActiveRecord::Migration[6.1]
def change
add_belongs_to :authorities, :uncollected_works_collection,
foreign_key: { to_table: :collections}, index: { unique: true }, type: :integer

end
end
5 changes: 4 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.define(version: 2024_07_07_201410) do
ActiveRecord::Schema.define(version: 2024_07_19_103532) do

create_table "aboutnesses", id: :integer, charset: "utf8mb4", collation: "utf8mb4_bin", force: :cascade do |t|
t.integer "work_id"
Expand Down Expand Up @@ -158,6 +158,7 @@
t.integer "person_id"
t.integer "corporate_body_id"
t.integer "root_collection_id"
t.integer "uncollected_works_collection_id"
t.index ["corporate_body_id"], name: "index_authorities_on_corporate_body_id", unique: true
t.index ["impressions_count"], name: "index_authorities_on_impressions_count"
t.index ["intellectual_property"], name: "index_authorities_on_intellectual_property"
Expand All @@ -167,6 +168,7 @@
t.index ["sort_name"], name: "index_authorities_on_sort_name"
t.index ["status", "published_at"], name: "index_authorities_on_status_and_published_at"
t.index ["toc_id"], name: "people_toc_id_fk"
t.index ["uncollected_works_collection_id"], name: "index_authorities_on_uncollected_works_collection_id", unique: true
end

create_table "base_user_preferences", id: :integer, charset: "utf8mb4", collation: "utf8mb4_bin", force: :cascade do |t|
Expand Down Expand Up @@ -1075,6 +1077,7 @@
add_foreign_key "anthology_texts", "anthologies"
add_foreign_key "anthology_texts", "manifestations"
add_foreign_key "authorities", "collections", column: "root_collection_id"
add_foreign_key "authorities", "collections", column: "uncollected_works_collection_id"
add_foreign_key "authorities", "corporate_bodies"
add_foreign_key "authorities", "people"
add_foreign_key "authorities", "tocs", name: "people_toc_id_fk"
Expand Down
13 changes: 4 additions & 9 deletions spec/factories/collections.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,10 @@

FactoryBot.define do
factory :collection do
title { 'MyString' }
sort_title { 'MyString' }
subtitle { 'MyString' }
title { Faker::Book.title }
sort_title { title }
subtitle { Faker::Book.title }
issn { 'MyString' }
collection_type { 1 }
inception { 'MyString' }
inception_year { 1 }
publication { nil }
toc { nil }
toc_strategy { 1 }
collection_type { %w(volume periodical periodical_issue series other).sample }
end
end
7 changes: 7 additions & 0 deletions spec/factories/manifestations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
primary { true }
expression_date { '2 ביוני 1960' }
work_date { '3 ביוני 1960' }
collections { [] }
end

title { "Title for #{manifestation_name}" }
Expand Down Expand Up @@ -47,6 +48,12 @@
)
end

collection_items do
collections.map do |c|
build(:collection_item, collection: c)
end
end

trait :with_external_links do
external_links { build_list(:external_link, 2) }
end
Expand Down
56 changes: 55 additions & 1 deletion spec/models/authority_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

describe Authority do
describe 'validations' do
it 'considers empty Person invalid' do
it 'considers empty Authority invalid' do
a = described_class.new
expect(a).not_to be_valid
end
Expand All @@ -18,6 +18,60 @@
expect(a).to be_valid
end

describe 'root collection type validation' do
let(:authority) { build(:authority, root_collection: root_collection) }

context 'when root collection is not set' do
let(:root_collection) { nil }

it { expect(authority).to be_valid }
end

context 'when root collection is set and has root type' do
let(:root_collection) { create(:collection, collection_type: :root) }

it { expect(authority).to be_valid }
end

context 'when root collection is set but has wrong type' do
let(:root_collection) { create(:collection) }

it 'fails validation' do
expect(authority).not_to be_valid
expect(authority.errors[:root_collection]).to eq [
I18n.t('activerecord.errors.models.authority.wrong_collection_type', expected_type: :root)
]
end
end
end

describe 'uncollected works collection type validation' do
let(:authority) { build(:authority, uncollected_works_collection: uncollected_works_collection) }

context 'when root collection is not set' do
let(:uncollected_works_collection) { nil }

it { expect(authority).to be_valid }
end

context 'when root collection is set and has uncollected type' do
let(:uncollected_works_collection) { create(:collection, collection_type: :uncollected) }

it { expect(authority).to be_valid }
end

context 'when root collection is set but has wrong type' do
let(:uncollected_works_collection) { create(:collection) }

it 'fails validation' do
expect(authority).not_to be_valid
expect(authority.errors[:uncollected_works_collection]).to eq [
I18n.t('activerecord.errors.models.authority.wrong_collection_type', expected_type: :uncollected)
]
end
end
end

describe '.validate_linked_authority' do
subject(:result) { authority.valid? }

Expand Down
Loading

0 comments on commit 324e7fc

Please sign in to comment.