enju_biblio 0.3.6 → 0.3.7

Sign up to get free protection for your applications and to get access to all the features.
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
  #