enju_biblio 0.3.6 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/items_controller.rb +5 -1
  3. data/app/controllers/manifestations_controller.rb +13 -7
  4. data/app/models/custom_property.rb +17 -0
  5. data/app/models/item.rb +51 -2
  6. data/app/models/manifestation.rb +110 -245
  7. data/app/models/resource_export_file.rb +3 -7
  8. data/app/models/resource_export_file_state_machine.rb +1 -1
  9. data/app/views/items/_custom_property_fields.html.erb +7 -0
  10. data/app/views/items/_form.html.erb +18 -6
  11. data/app/views/items/show.html.erb +7 -0
  12. data/app/views/manifestations/_custom_property_fields.html.erb +7 -0
  13. data/app/views/manifestations/_form.html.erb +10 -0
  14. data/app/views/manifestations/_manifestation.txt.erb +1 -1
  15. data/app/views/manifestations/_show_detail_librarian.html.erb +8 -0
  16. data/app/views/manifestations/index.txt.ruby +7 -0
  17. data/app/views/manifestations/show.txt.ruby +5 -0
  18. data/app/views/resource_import_files/_results.html.erb +6 -0
  19. data/app/views/resource_import_results/index.html.erb +0 -11
  20. data/app/views/series_statements/_form.html.erb +6 -8
  21. data/app/views/series_statements/show.html.erb +12 -0
  22. data/config/locales/translation_en.yml +7 -0
  23. data/config/locales/translation_ja.yml +10 -3
  24. data/db/migrate/20191219122214_create_custom_properties.rb +12 -0
  25. data/lib/enju_biblio/version.rb +1 -1
  26. data/spec/controllers/items_controller_spec.rb +25 -0
  27. data/spec/controllers/manifestations_controller_spec.rb +25 -0
  28. data/spec/dummy/db/schema.rb +10 -1
  29. data/spec/factories/custom_property.rb +18 -0
  30. data/spec/factories/series_statement.rb +4 -3
  31. data/spec/fixtures/items.yml +11 -10
  32. data/spec/fixtures/manifestations.yml +1 -0
  33. data/spec/models/custom_property_spec.rb +18 -0
  34. data/spec/models/item_spec.rb +1 -0
  35. data/spec/models/manifestation_spec.rb +33 -7
  36. data/spec/rails_helper.rb +3 -3
  37. data/spec/system/custom_properties_spec.rb +84 -0
  38. data/spec/system/series_statements_spec.rb +16 -0
  39. data/spec/views/manifestations/{index.txt.erb_spec.rb → index.txt.ruby_spec.rb} +1 -1
  40. data/spec/views/manifestations/{show.txt.erb_spec.rb → show.txt.ruby_spec.rb} +1 -1
  41. metadata +504 -492
  42. data/app/views/manifestations/index.txt.erb +0 -1
  43. data/app/views/manifestations/show.txt.erb +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c5d6d8f73b0961bc27b8d475802d2d22372f06e77fc380daba1a2c57f16b1f5
4
- data.tar.gz: 19afaf59c4800afacbe0c7457414527f0dd46e1c1966212845739e168552cf5d
3
+ metadata.gz: bb38665a417d9e1788c1d171ac936357450704fd4d8ab7e87bbc02b1fe964aa1
4
+ data.tar.gz: 318c358c22dd3df104b6e2b4353e6b7d4758994f6fde55401e8fdac97345750a
5
5
  SHA512:
6
- metadata.gz: 8821f0a2291b6f03aaaa528985fa7bd9240a0f7cf50fa97d8689e1edf287766aeff6b9e61dec69797a23e367e91c989bf96a30910dfd6470b2e0c99edf51df40
7
- data.tar.gz: 59247ed9b84ec043a99f8b6d7b68bc79b8454dc0fe19c38611b8081b8d873cc885bda488ddeb7bfd9fa7c71b1f3d8bba37ecbc28e0f7c84d77336ea64e7a2b8a
6
+ metadata.gz: e90ea6fdc7120d2ce1456862cd5e55baafa9403f85af50119ad2b6dea81dd251f924025ef70d27a1c9060f7364ffb391eae7a22b0f5e08ea36201191b42687e5
7
+ data.tar.gz: 2c15b0e9b79fda1c4e7164a49a9048ab8d024e5748ec72ca295ab68f3da67d2cac07053de6848577fcdd98507abd0f4d095a832d6676dedca6411c3a9e1f7c9d
@@ -273,7 +273,11 @@ class ItemsController < ApplicationController
273
273
  :lock_version, :manifestation_id, :library_id, :required_role_id,
274
274
  :binding_item_identifier, :binding_call_number, :binded_at,
275
275
  :use_restriction_id, :memo,
276
- item_has_use_restriction_attributes: :use_restriction_id # EnjuCirculation
276
+ {item_has_use_restriction_attributes: :use_restriction_id}, # EnjuCirculation
277
+ {custom_properties_attributes: [
278
+ :id, :label, :value,
279
+ :_destroy
280
+ ]}
277
281
  )
278
282
  end
279
283
 
@@ -429,15 +429,17 @@ class ManifestationsController < ApplicationController
429
429
  # PUT /manifestations/1.json
430
430
  def update
431
431
  creators_params = manifestation_params[:creators_attributes]
432
- Manifestation.transaction do
433
- @manifestation.assign_attributes(manifestation_params.delete_if{|k, v|
434
- k == 'creators_attributes'
435
- })
436
- @manifestation.creators = Agent.new_agents(creators_params)
437
- end
432
+ @manifestation.assign_attributes(manifestation_params.delete_if{|k, v|
433
+ k == 'creators_attributes'
434
+ })
438
435
 
439
436
  respond_to do |format|
440
- if @manifestation.save
437
+ if @manifestation.valid?
438
+ Manifestation.transaction do
439
+ @manifestation.creators = Agent.new_agents(creators_params)
440
+ @manifestation.save!
441
+ end
442
+
441
443
  format.html { redirect_to @manifestation, notice: t('controller.successfully_updated', model: t('activerecord.models.manifestation')) }
442
444
  format.json { head :no_content }
443
445
  else
@@ -547,6 +549,10 @@ class ManifestationsController < ApplicationController
547
549
  {identifiers_attributes: [
548
550
  :id, :body, :identifier_type_id,
549
551
  :_destroy
552
+ ]},
553
+ {custom_properties_attributes: [
554
+ :id, :label, :value,
555
+ :_destroy
550
556
  ]}
551
557
  )
552
558
  end
@@ -0,0 +1,17 @@
1
+ class CustomProperty < ApplicationRecord
2
+ belongs_to :resource, polymorphic: true
3
+ validates :label, presence: true
4
+ end
5
+
6
+ # == Schema Information
7
+ #
8
+ # Table name: custom_properties
9
+ #
10
+ # id :integer not null, primary key
11
+ # resource_id :integer not null
12
+ # resource_type :string not null
13
+ # label :text not null
14
+ # value :text
15
+ # created_at :datetime not null
16
+ # updated_at :datetime not null
17
+ #
@@ -17,8 +17,10 @@ class Item < ApplicationRecord
17
17
  belongs_to :bookstore, optional: true
18
18
  belongs_to :required_role, class_name: 'Role', foreign_key: 'required_role_id'
19
19
  belongs_to :budget_type, optional: true
20
- has_one :accept
21
- has_one :withdraw
20
+ has_one :accept, dependent: :destroy
21
+ has_one :withdraw, dependent: :destroy
22
+ has_many :custom_properties, as: :resource, dependent: :destroy
23
+ accepts_nested_attributes_for :custom_properties, allow_destroy: true, reject_if: :all_blank
22
24
  scope :accepted_between, lambda{|from, to| includes(:accept).where('items.created_at BETWEEN ? AND ?', Time.zone.parse(from).beginning_of_day, Time.zone.parse(to).end_of_day)}
23
25
 
24
26
  belongs_to :shelf, counter_cache: true
@@ -96,6 +98,52 @@ class Item < ApplicationRecord
96
98
  true
97
99
  end
98
100
  end
101
+
102
+ def self.csv_header(role: 'Guest')
103
+ Item.new.to_hash(role: role).keys
104
+ end
105
+
106
+ def to_hash(role: 'Guest')
107
+ record = {
108
+ item_id: id,
109
+ item_identifier: item_identifier,
110
+ call_number: call_number,
111
+ shelf: shelf.name,
112
+ item_note: note,
113
+ accepted_at: accept.try(:created_at),
114
+ acquired_at: acquired_at,
115
+ item_created_at: created_at,
116
+ item_updated_at: updated_at
117
+ }
118
+
119
+ if ['Administrator', 'Librarian'].include?(role)
120
+ record.merge!({
121
+ bookstore: bookstore.try(:name),
122
+ budget_type: budget_type.try(:name),
123
+ item_price: price,
124
+ memo: memo
125
+ })
126
+
127
+ # 最もカスタム項目の多い資料について、カスタム項目の個数を取得する
128
+ ActiveRecord::Base.connection.execute('SELECT max(record_count) FROM (SELECT count(*) AS record_count, resource_id, resource_type FROM custom_properties GROUP BY resource_id, resource_type) AS type_count ;').first.values[0].to_i.times do |i|
129
+ property = custom_properties[i]
130
+ if property
131
+ record[:"item_custom_property_#{i + 1}"] = "#{property.label}: #{property.value}"
132
+ else
133
+ record[:"item_custom_property_#{i + 1}"] = nil
134
+ end
135
+ end
136
+
137
+ if defined?(EnjuCirculation)
138
+ record.merge!({
139
+ use_restriction: use_restriction.try(:name),
140
+ total_checkouts: checkouts.count
141
+ })
142
+ end
143
+ end
144
+
145
+ record
146
+ end
99
147
  end
100
148
 
101
149
  # == Schema Information
@@ -125,4 +173,5 @@ end
125
173
  # binding_call_number :string
126
174
  # binded_at :datetime
127
175
  # manifestation_id :integer not null
176
+ # memo :text
128
177
  #
@@ -25,11 +25,13 @@ class Manifestation < ApplicationRecord
25
25
  belongs_to :required_role, class_name: 'Role', foreign_key: 'required_role_id'
26
26
  has_one :resource_import_result
27
27
  has_many :identifiers, dependent: :destroy
28
+ has_many :custom_properties, as: :resource, dependent: :destroy
28
29
  accepts_nested_attributes_for :creators, allow_destroy: true, reject_if: :all_blank
29
30
  accepts_nested_attributes_for :contributors, allow_destroy: true, reject_if: :all_blank
30
31
  accepts_nested_attributes_for :publishers, allow_destroy: true, reject_if: :all_blank
31
32
  accepts_nested_attributes_for :series_statements, allow_destroy: true, reject_if: :all_blank
32
33
  accepts_nested_attributes_for :identifiers, allow_destroy: true, reject_if: :all_blank
34
+ accepts_nested_attributes_for :custom_properties, allow_destroy: true, reject_if: :all_blank
33
35
 
34
36
  searchable do
35
37
  text :title, default_boost: 2 do
@@ -528,266 +530,128 @@ class Manifestation < ApplicationRecord
528
530
  end
529
531
  end
530
532
 
531
- def self.csv_header(role, options = {col_sep: "\t", role: :Guest})
532
- header = %w(
533
- manifestation_id
534
- original_title
535
- title_transcription
536
- creator
537
- contributor
538
- publisher
539
- pub_date
540
- statement_of_responsibility
541
- manifestation_price
542
- manifestation_created_at
543
- manifestation_updated_at
544
- manifestation_identifier
545
- access_address
546
- description
547
- note
548
- extent
549
- dimensions
550
- carrier_type
551
- edition
552
- edition_string
553
- volume_number
554
- volume_number_string
555
- issue_number
556
- issue_number_string
557
- serial_number
533
+ # CSVのヘッダ
534
+ # @param [String] role 権限
535
+ def self.csv_header(role: 'Guest')
536
+ Manifestation.new.to_hash(role: role).keys
537
+ end
538
+
539
+ # CSV出力用のハッシュ
540
+ # @param [String] role 権限
541
+ def to_hash(role: 'Guest')
542
+ record = {
543
+ manifestation_id: id,
544
+ title: original_title,
545
+ title_alternative: title_alternative,
546
+ title_transcription: title_transcription,
547
+ statement_of_responsibility: statement_of_responsibility,
548
+ serial: serial,
549
+ manifestation_identifier: manifestation_identifier,
550
+ creator: creators.pluck(:full_name).join('//'),
551
+ contributor: contributors.pluck(:full_name).join('//'),
552
+ publisher: publishers.pluck(:full_name).join('//'),
553
+ date_of_publication: date_of_publication,
554
+ year_of_publication: year_of_publication,
555
+ publication_place: publication_place,
556
+ manifestation_created_at: created_at,
557
+ manifestation_updated_at: updated_at,
558
+ carrier_type: carrier_type.name,
559
+ content_type: manifestation_content_type.name,
560
+ frequency: frequency.name,
561
+ language: language.name,
562
+ isbn: identifier_contents(:isbn).join('//'),
563
+ issn: identifier_contents(:issn).join('//'),
564
+ volume_number: volume_number,
565
+ volume_number_string: volume_number_string,
566
+ edition: edition,
567
+ edition_string: edition_string,
568
+ issue_number: issue_number,
569
+ issue_number_string: issue_number_string,
570
+ serial_number: serial_number,
571
+ extent: extent,
572
+ start_page: start_page,
573
+ end_page: end_page,
574
+ dimensions: dimensions,
575
+ height: height,
576
+ width: width,
577
+ depth: depth,
578
+ price: price,
579
+ access_address: access_address,
580
+ required_role: required_role.name,
581
+ description: description,
582
+ note: note
583
+ }
584
+
585
+ IdentifierType.find_each do |type|
586
+ record[type.name.to_sym] = identifiers.where(identifier_type: type).pluck(:body).join('//')
587
+ end
588
+
589
+ series = series_statements.order(:position)
590
+ record.merge!(
591
+ series_statement_id: series.pluck(:id).join('//'),
592
+ series_statement_original_title: series.pluck(:original_title).join('.//'),
593
+ series_statement_title_subseries: series.pluck(:title_subseries).join('//'),
594
+ series_statement_title_subseries_transcription: series.pluck(:title_subseries_transcription).join('//'),
595
+ series_statement_title_transcription: series.pluck(:title_transcription).join('//'),
596
+ series_statement_creator: series.pluck(:creator_string).join('//'),
597
+ series_statement_volume_number: series.pluck(:volume_number_string).join('//'),
598
+ series_statement_series_master: series.pluck(:series_master).join('//'),
599
+ series_statement_root_manifestation_id: series.pluck(:root_manifestation_id).join('//'),
600
+ series_statement_manifestation_id: series.pluck(:manifestation_id).join('//'),
601
+ series_statement_position: series.pluck(:position).join('//'),
602
+ series_statement_note: series.pluck(:note).join('//'),
603
+ series_statement_created_at: series.pluck(:created_at).join('//'),
604
+ series_statement_updated_at: series.pluck(:updated_at).join('//')
558
605
  )
559
606
 
560
- header += IdentifierType.order(:position).pluck(:name)
561
- if defined?(EnjuSubject)
562
- header += SubjectHeadingType.order(:position).pluck(:name).map{|type| "subject:#{type}"}
563
- header += ClassificationType.order(:position).pluck(:name).map{|type| "classification:#{type}"}
564
- end
607
+ if ['Administrator', 'Librarian'].include?(role)
608
+ record.merge!({
609
+ memo: memo
610
+ })
565
611
 
566
- header += %w(
567
- item_id
568
- item_identifier
569
- call_number
570
- item_note
571
- )
572
- case role.to_sym
573
- when :Administrator, :Librarian
574
- header << "item_price"
612
+ # 最もカスタム項目の多い資料について、カスタム項目の個数を取得する
613
+ ActiveRecord::Base.connection.execute('SELECT max(record_count) FROM (SELECT count(*) AS record_count, resource_id, resource_type FROM custom_properties GROUP BY resource_id, resource_type) AS type_count ;').first.values[0].to_i.times do |i|
614
+ property = custom_properties[i]
615
+ if property
616
+ record[:"manifestation_custom_property_#{i + 1}"] = "#{property.label}: #{property.value}"
617
+ else
618
+ record[:"manifestation_custom_property_#{i + 1}"] = nil
619
+ end
620
+ end
575
621
  end
576
- header += %w(
577
- acquired_at
578
- accepted_at
579
- )
580
- case role.to_sym
581
- when :Administrator, :Librarian
582
- header += %w(
583
- bookstore
584
- budget_type
585
- total_checkouts
586
- )
587
- end
588
- header += %w(
589
- circulation_status
590
- shelf
591
- library
592
- item_created_at
593
- item_updated_at
594
- )
595
- case role.to_sym
596
- when :Administrator, :Librarian
597
- header << "use_restriction"
622
+
623
+ if defined?(EnjuSubject)
624
+ SubjectHeadingType.find_each do |type|
625
+ record[:"subject:#{type.name}"] = subjects.where(subject_heading_type: type).pluck(:term).join('//')
626
+ end
627
+ ClassificationType.find_each do |type|
628
+ record[:"classification:#{type.name}"] = classifications.where(classification_type: type).pluck(:category).join('//')
629
+ end
598
630
  end
599
631
 
600
- header.to_csv(options)
632
+ record
601
633
  end
602
634
 
603
- def to_csv(options = {format: :txt, role: :Guest})
604
- lines = []
605
- if items.exists?
606
- items.includes(shelf: :library).each do |i|
607
- item_lines = []
608
- item_lines << id
609
- item_lines << original_title
610
- item_lines << title_transcription
611
- if creators.exists?
612
- item_lines << creators.pluck(:full_name).join("//")
613
- else
614
- item_lines << nil
615
- end
616
- if contributors.exists?
617
- item_lines << contributors.pluck(:full_name).join("//")
618
- else
619
- item_lines << nil
620
- end
621
- if publishers.exists?
622
- item_lines << publishers.pluck(:full_name).join("//")
623
- else
624
- item_lines << nil
625
- end
626
- item_lines << pub_date
627
- item_lines << statement_of_responsibility
628
- item_lines << price
629
- item_lines << created_at
630
- item_lines << updated_at
631
- item_lines << manifestation_identifier
632
- item_lines << access_address
633
- item_lines << description.try(:gsub, /\r?\n/, '\n')
634
- item_lines << note.try(:gsub, /\r?\n/, '\n')
635
- item_lines << extent
636
- item_lines << dimensions
637
- item_lines << carrier_type.name
638
- item_lines << edition
639
- item_lines << edition_string
640
- item_lines << volume_number
641
- item_lines << volume_number_string
642
- item_lines << issue_number
643
- item_lines << issue_number_string
644
- item_lines << serial_number
645
-
646
- IdentifierType.order(:position).pluck(:name).each do |identifier_type|
647
- identifier_list = identifier_contents(identifier_type.to_sym)
648
- if identifier_list
649
- item_lines << identifier_list.join("//")
650
- else
651
- item_lines << nil
635
+ # TSVでのエクスポート
636
+ # @param [String] role 権限
637
+ # @param [String] col_sep 区切り文字
638
+ def self.export(role: 'Guest', col_sep: "\t")
639
+ file = Tempfile.create('manifestation_export') do |f|
640
+ f.write (Manifestation.csv_header(role: role) + Item.csv_header(role: role)).to_csv(col_sep: col_sep)
641
+ Manifestation.find_each do |manifestation|
642
+ if manifestation.items.exists?
643
+ manifestation.items.each do |item|
644
+ f.write (manifestation.to_hash(role: role).values + item.to_hash(role: role).values).to_csv(col_sep: col_sep)
652
645
  end
653
- end
654
- if defined?(EnjuSubject)
655
- SubjectHeadingType.order(:position).each do |subject_heading_type|
656
- if subjects.exists?
657
- item_lines << subjects.where(subject_heading_type: subject_heading_type).pluck(:term).join('//')
658
- else
659
- item_lines << nil
660
- end
661
- end
662
- ClassificationType.order(:position).each do |classification_type|
663
- if classifications.exists?
664
- item_lines << classifications.where(classification_type: classification_type).pluck(:category).join('//')
665
- else
666
- item_lines << nil
667
- end
668
- end
669
- end
670
-
671
- item_lines << i.id
672
- item_lines << i.item_identifier
673
- item_lines << i.call_number
674
- item_lines << i.note.try(:gsub, /\r?\n/, '\n')
675
- case options[:role].to_sym
676
- when :Administrator, :Librarian
677
- item_lines << i.price
678
- end
679
- item_lines << i.acquired_at
680
- item_lines << i.accept.try(:created_at)
681
- case options[:role].to_sym
682
- when :Administrator, :Librarian
683
- item_lines << i.bookstore.try(:name)
684
- item_lines << i.budget_type.try(:name)
685
- if defined?(EnjuCirculation)
686
- item_lines << Checkout.where(item_id: i.id).count
687
- else
688
- item_lines << ''
689
- end
690
- end
691
- if defined?(EnjuCirculation)
692
- item_lines << i.circulation_status.try(:name)
693
- else
694
- item_lines << ''
695
- end
696
- item_lines << i.shelf.name
697
- item_lines << i.shelf.library.name
698
- item_lines << i.created_at
699
- item_lines << i.updated_at
700
- case options[:role].to_sym
701
- when :Administrator, :Librarian
702
- if defined?(EnjuCirculation)
703
- item_lines << i.use_restriction.try(:name)
704
- else
705
- item_lines << ''
706
- end
707
- end
708
- lines << item_lines
709
- end
710
- else
711
- line = []
712
- line << id
713
- line << original_title
714
- line << title_transcription
715
- if creators.exists?
716
- line << creators.pluck(:full_name).join("//")
717
- else
718
- line << nil
719
- end
720
- if contributors.exists?
721
- line << contributors.pluck(:full_name).join("//")
722
- else
723
- line << nil
724
- end
725
- if publishers.exists?
726
- line << publishers.pluck(:full_name).join("//")
727
- else
728
- line << nil
729
- end
730
- line << pub_date
731
- line << statement_of_responsibility
732
- line << price
733
- line << created_at
734
- line << updated_at
735
- line << manifestation_identifier
736
- line << access_address
737
- line << description.try(:gsub, /\r?\n/, '\n')
738
- line << note.try(:gsub, /\r?\n/, '\n')
739
- line << extent
740
- line << dimensions
741
- line << carrier_type.name
742
- line << edition
743
- line << edition_string
744
- line << volume_number
745
- line << volume_number_string
746
- line << issue_number
747
- line << issue_number_string
748
- line << serial_number
749
-
750
- IdentifierType.order(:position).pluck(:name).each do |identifier_type|
751
- identifier_list = identifier_contents(identifier_type.to_sym)
752
- if identifier_list
753
- line << identifier_list.join("//")
754
646
  else
755
- line << nil
756
- end
757
- end
758
- if defined?(EnjuSubject)
759
- SubjectHeadingType.order(:position).each do |subject_heading_type|
760
- if subjects.exists?
761
- line << subjects.where(subject_heading_type: subject_heading_type).pluck(:term).join('//')
762
- else
763
- line << nil
764
- end
765
- end
766
- ClassificationType.order(:position).each do |classification_type|
767
- if classifications.exists?
768
- line << classifications.where(classification_type: classification_type).pluck(:category).join('//')
769
- else
770
- line << nil
771
- end
647
+ f.write manifestation.to_hash(role: role).values.to_csv(col_sep: col_sep)
772
648
  end
773
649
  end
774
650
 
775
- lines << line
776
- end
777
-
778
- if options[:format] == :txt
779
- lines.map{|i| i.to_csv(col_sep: "\t")}.join
780
- else
781
- lines
651
+ f.rewind
652
+ f.read
782
653
  end
783
- end
784
654
 
785
- def self.export(options = {format: :txt, role: :Guest})
786
- file = ''
787
- file += Manifestation.csv_header(options[:role], col_sep: "\t") if options[:format].to_sym == :txt
788
- Manifestation.find_each do |manifestation|
789
- file += manifestation.to_csv(options)
790
- end
791
655
  file
792
656
  end
793
657
 
@@ -872,4 +736,5 @@ end
872
736
  # publication_place :text
873
737
  # extent :text
874
738
  # dimensions :text
739
+ # memo :text
875
740
  #