sufia 0.0.1.pre2 → 0.0.1

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 (169) hide show
  1. data/Gemfile +2 -5
  2. data/README.md +44 -12
  3. data/app/assets/javascripts/{scholarsphere.js → sufia.js} +0 -0
  4. data/app/assets/stylesheets/{scholarsphere.css → sufia.css} +0 -0
  5. data/app/controllers/batch_controller.rb +2 -3
  6. data/app/controllers/batch_edits_controller.rb +4 -4
  7. data/app/controllers/dashboard_controller.rb +5 -3
  8. data/app/controllers/generic_files_controller.rb +77 -41
  9. data/app/controllers/users_controller.rb +9 -21
  10. data/app/helpers/blacklight/render_constraints_helper_behavior.rb +2 -2
  11. data/app/helpers/sufia_helper.rb +23 -2
  12. data/app/models/datastreams/file_content_datastream.rb +17 -9
  13. data/app/models/generic_file.rb +1 -809
  14. data/app/views/_add_assets_links.html.erb +1 -1
  15. data/app/views/_user_util_links.html.erb +2 -2
  16. data/app/views/batch/_metadata.html.erb +16 -16
  17. data/app/views/batch/edit.html.erb +16 -10
  18. data/app/views/batch_edits/_metadata.html.erb +16 -16
  19. data/app/views/catalog/_index_partials/_list_files.html.erb +2 -2
  20. data/app/views/catalog/index.html.erb +5 -0
  21. data/app/views/dashboard/_facet_limit.html.erb +1 -1
  22. data/app/views/dashboard/_facet_pagination.html.erb +4 -4
  23. data/app/views/dashboard/_facet_selected.html.erb +1 -1
  24. data/app/views/dashboard/_index_partials/_list_files.html.erb +8 -8
  25. data/app/views/dashboard/_search_form.html.erb +1 -1
  26. data/app/views/dashboard/_sort_and_per_page.html.erb +1 -1
  27. data/app/views/dashboard/index.html.erb +0 -1
  28. data/app/views/generic_files/_breadcrumbs.html.erb +1 -1
  29. data/app/views/generic_files/_descriptions.html.erb +3 -3
  30. data/app/views/generic_files/_field_form +3 -3
  31. data/app/views/generic_files/_media_display.html.erb +5 -4
  32. data/app/views/generic_files/_permission.html.erb +5 -5
  33. data/app/views/generic_files/_versioning.html.erb +1 -1
  34. data/app/views/generic_files/edit.html.erb +2 -2
  35. data/app/views/generic_files/show.html.erb +3 -3
  36. data/app/views/static/versions.html.erb +1 -1
  37. data/app/views/users/edit.html.erb +5 -3
  38. data/app/views/users/index.html.erb +3 -3
  39. data/app/views/users/show.html.erb +6 -6
  40. data/config/jetty.yml +6 -0
  41. data/config/routes.rb +8 -4
  42. data/features/browse_dashboard_files.feature +11 -1
  43. data/features/browse_files.feature +6 -5
  44. data/features/contact_form.feature +4 -0
  45. data/features/display_dashboard.feature +6 -3
  46. data/features/ingest_upload_files.feature +2 -2
  47. data/features/step_definitions/fixture_steps.rb +6 -5
  48. data/features/step_definitions/scholarsphere.rb +24 -1
  49. data/features/step_definitions/user_steps.rb +2 -2
  50. data/features/step_definitions/web_steps.rb +1 -1
  51. data/features/support/env.rb +26 -0
  52. data/features/users.feature +18 -0
  53. data/lib/active_support/core_ext/marshal.rb +22 -0
  54. data/lib/generators/sufia/sufia_generator.rb +18 -2
  55. data/lib/generators/sufia/templates/catalog_controller.rb +3 -4
  56. data/{spec/support → lib/generators/sufia/templates}/config/redis.yml +0 -0
  57. data/lib/generators/sufia/templates/config/sufia.rb +68 -0
  58. data/lib/generators/sufia/templates/migrations/add_ldap_attrs_to_user.rb +41 -0
  59. data/lib/kaminari/helpers/tag.rb +11 -0
  60. data/lib/sufia.rb +30 -7
  61. data/lib/sufia/controller.rb +1 -5
  62. data/lib/sufia/generic_file.rb +200 -0
  63. data/lib/sufia/generic_file/audit.rb +119 -0
  64. data/lib/sufia/generic_file/characterization.rb +82 -0
  65. data/lib/sufia/generic_file/export.rb +339 -0
  66. data/lib/sufia/generic_file/permissions.rb +64 -0
  67. data/lib/sufia/generic_file/thumbnail.rb +68 -0
  68. data/{app/models → lib/sufia/jobs}/audit_job.rb +13 -3
  69. data/lib/sufia/jobs/batch_update_job.rb +86 -0
  70. data/lib/sufia/jobs/characterize_job.rb +35 -0
  71. data/{app/models → lib/sufia/jobs}/content_delete_event_job.rb +3 -1
  72. data/{app/models → lib/sufia/jobs}/content_deposit_event_job.rb +1 -1
  73. data/{app/models → lib/sufia/jobs}/content_new_version_event_job.rb +1 -1
  74. data/{app/models → lib/sufia/jobs}/content_restored_version_event_job.rb +8 -0
  75. data/{app/models → lib/sufia/jobs}/content_update_event_job.rb +1 -1
  76. data/{app/models → lib/sufia/jobs}/event_job.rb +7 -3
  77. data/{app/models → lib/sufia/jobs}/resolrize_job.rb +4 -2
  78. data/lib/sufia/jobs/transcode_video_job.rb +79 -0
  79. data/{app/models → lib/sufia/jobs}/unzip_job.rb +11 -3
  80. data/{app/models → lib/sufia/jobs}/user_edit_profile_event_job.rb +6 -0
  81. data/{app/models → lib/sufia/jobs}/user_follow_event_job.rb +9 -4
  82. data/{app/models → lib/sufia/jobs}/user_unfollow_event_job.rb +6 -0
  83. data/lib/sufia/queue/resque.rb +30 -0
  84. data/lib/sufia/role_mapper.rb +0 -1
  85. data/{app/models/characterize_job.rb → lib/sufia/solr_document_behavior.rb} +6 -7
  86. data/lib/sufia/user.rb +3 -3
  87. data/lib/sufia/version.rb +1 -1
  88. data/lib/tasks/fixtures.rake +38 -38
  89. data/lib/tasks/resque.rake +1 -0
  90. data/solr_conf/conf/solrconfig.xml +32 -1615
  91. data/solr_conf/solr.xml +1 -1
  92. data/spec/active_fedora/unsaved_digital_object_spec.rb +4 -4
  93. data/spec/config/host_to_vhost_spec.rb +4 -4
  94. data/spec/controllers/authorities_controller_spec.rb +1 -1
  95. data/spec/controllers/batch_controller_spec.rb +12 -10
  96. data/spec/controllers/catalog_controller_spec.rb +13 -13
  97. data/spec/controllers/dashboard_controller_spec.rb +15 -15
  98. data/spec/controllers/downloads_controller_spec.rb +14 -14
  99. data/spec/controllers/generic_files_controller_spec.rb +88 -46
  100. data/spec/controllers/mailbox_controller_spec.rb +2 -2
  101. data/spec/controllers/sessions_controller_spec.rb +1 -1
  102. data/spec/controllers/single_use_link_controller_spec.rb +18 -18
  103. data/spec/controllers/users_controller_spec.rb +47 -31
  104. data/spec/fixtures/countdown.avi +0 -0
  105. data/spec/fixtures/sufia/.gitignore +1 -0
  106. data/spec/fixtures/{scholarsphere → sufia}/bg_header.jpg +0 -0
  107. data/spec/fixtures/sufia/sufia_test1.descMeta.txt +12 -0
  108. data/spec/fixtures/{scholarsphere → sufia}/sufia_test1.foxml.erb +2 -2
  109. data/spec/fixtures/{scholarsphere/scholarsphere_test1.txt → sufia/sufia_test1.txt} +0 -0
  110. data/spec/fixtures/sufia/sufia_test2.descMeta.txt +12 -0
  111. data/spec/fixtures/{scholarsphere/scholarsphere_test2.docx → sufia/sufia_test2.docx} +0 -0
  112. data/spec/fixtures/{scholarsphere/scholarsphere_test2.foxml.erb → sufia/sufia_test2.foxml.erb} +6 -6
  113. data/spec/fixtures/sufia/sufia_test3.descMeta.txt +12 -0
  114. data/spec/fixtures/{scholarsphere/scholarsphere_test3.foxml.erb → sufia/sufia_test3.foxml.erb} +6 -6
  115. data/spec/fixtures/{scholarsphere/scholarsphere_test3.xls → sufia/sufia_test3.xls} +0 -0
  116. data/spec/fixtures/sufia/sufia_test4.descMeta.txt +12 -0
  117. data/spec/fixtures/{scholarsphere/scholarsphere_test4.foxml.erb → sufia/sufia_test4.foxml.erb} +6 -6
  118. data/spec/fixtures/{scholarsphere/scholarsphere_test4.pdf → sufia/sufia_test4.pdf} +0 -0
  119. data/spec/fixtures/sufia/sufia_test5.descMeta.txt +19 -0
  120. data/spec/fixtures/{scholarsphere → sufia}/sufia_test5.foxml.erb +3 -3
  121. data/spec/fixtures/{scholarsphere/scholarsphere_test5.mp3 → sufia/sufia_test5.mp3} +0 -0
  122. data/spec/fixtures/sufia/sufia_test5.txt +1 -0
  123. data/spec/fixtures/sufia/sufia_test6.descMeta.txt +12 -0
  124. data/spec/fixtures/{scholarsphere/scholarsphere_test6.foxml.erb → sufia/sufia_test6.foxml.erb} +6 -6
  125. data/spec/fixtures/{scholarsphere/scholarsphere_test6.jp2 → sufia/sufia_test6.jp2} +0 -0
  126. data/spec/fixtures/sufia/sufia_test6.txt +1 -0
  127. data/spec/fixtures/sufia_generic_stub.descMeta.txt +12 -0
  128. data/spec/fixtures/{scholarsphere_generic_stub.foxml.erb → sufia_generic_stub.foxml.erb} +3 -3
  129. data/spec/fixtures/sufia_generic_stub.txt +1 -0
  130. data/spec/lib/sufia/role_mapper_spec.rb +1 -1
  131. data/spec/models/audit_job_spec.rb +8 -11
  132. data/spec/models/batch_spec.rb +5 -5
  133. data/spec/models/batch_update_job_spec.rb +18 -15
  134. data/spec/models/checksum_audit_log_spec.rb +6 -19
  135. data/spec/models/event_jobs_spec.rb +23 -23
  136. data/spec/models/file_content_datastream_spec.rb +14 -14
  137. data/spec/models/fits_datastream_spec.rb +1 -1
  138. data/spec/models/generic_file_spec.rb +88 -41
  139. data/spec/models/single_use_link_spec.rb +3 -3
  140. data/spec/models/transcode_video_job_spec.rb +30 -0
  141. data/spec/models/unzip_job_spec.rb +6 -4
  142. data/spec/rake/{scholarsphere_fixtures_spec.rb → sufia_fixtures_spec.rb} +16 -16
  143. data/spec/routing/route_spec.rb +4 -8
  144. data/spec/spec_helper.rb +0 -7
  145. data/spec/support/Gemfile +4 -2
  146. data/spec/support/fedora_conf/fedora.fcfg +953 -0
  147. data/spec/support/lib/generators/test_app_generator.rb +1 -11
  148. data/sufia.gemspec +5 -3
  149. data/tasks/{scholarsphere-db.rake → sufia-db.rake} +1 -1
  150. data/tasks/{scholarsphere-dev.rake → sufia-dev.rake} +7 -3
  151. data/tasks/{scholarsphere-fixtures.rake → sufia-fixtures.rake} +43 -43
  152. data/tasks/{scholarsphere.rake → sufia.rake} +2 -2
  153. metadata +126 -95
  154. data/app/models/batch_update_job.rb +0 -82
  155. data/app/models/solr_document.rb +0 -50
  156. data/lib/sufia/permissions.rb +0 -43
  157. data/spec/fixtures/scholarsphere/scholarsphere_test1.descMeta.txt +0 -12
  158. data/spec/fixtures/scholarsphere/scholarsphere_test2.descMeta.txt +0 -12
  159. data/spec/fixtures/scholarsphere/scholarsphere_test3.descMeta.txt +0 -12
  160. data/spec/fixtures/scholarsphere/scholarsphere_test4.descMeta.txt +0 -12
  161. data/spec/fixtures/scholarsphere/scholarsphere_test5.descMeta.txt +0 -19
  162. data/spec/fixtures/scholarsphere/scholarsphere_test5.txt +0 -1
  163. data/spec/fixtures/scholarsphere/scholarsphere_test6.descMeta.txt +0 -12
  164. data/spec/fixtures/scholarsphere/scholarsphere_test6.txt +0 -1
  165. data/spec/fixtures/scholarsphere/sufia_scholarsphere1.descMeta.txt +0 -12
  166. data/spec/fixtures/scholarsphere/sufia_scholarsphere1.foxml.erb +0 -79
  167. data/spec/fixtures/scholarsphere/sufia_scholarsphere1.txt +0 -1
  168. data/spec/fixtures/scholarsphere_generic_stub.descMeta.txt +0 -12
  169. data/spec/fixtures/scholarsphere_generic_stub.txt +0 -1
@@ -16,7 +16,7 @@ require 'open3'
16
16
  class FileContentDatastream < ActiveFedora::Datastream
17
17
  include Open3
18
18
 
19
- def extract_metadata
19
+ def to_tempfile &block
20
20
  return if content.nil?
21
21
  f = Tempfile.new("#{pid}-#{dsVersionID}")
22
22
  f.binmode
@@ -27,15 +27,23 @@ class FileContentDatastream < ActiveFedora::Datastream
27
27
  end
28
28
  f.close
29
29
  content.rewind if content.respond_to? :rewind
30
- command = "#{fits_path} -i #{f.path}"
31
- stdin, stdout, stderr = popen3(command)
32
- stdin.close
33
- out = stdout.read
34
- stdout.close
35
- err = stderr.read
36
- stderr.close
37
- raise "Unable to execute command \"#{command}\"\n#{err}" unless err.empty? or err.include? "Error parsing Exiftool XML Output"
30
+ yield(f)
38
31
  f.unlink
32
+
33
+ end
34
+
35
+ def extract_metadata
36
+ out = nil
37
+ to_tempfile do |f|
38
+ command = "#{fits_path} -i #{f.path}"
39
+ stdin, stdout, stderr = popen3(command)
40
+ stdin.close
41
+ out = stdout.read
42
+ stdout.close
43
+ err = stderr.read
44
+ stderr.close
45
+ raise "Unable to execute command \"#{command}\"\n#{err}" unless err.empty? or err.include? "Error parsing Exiftool XML Output"
46
+ end
39
47
  out
40
48
  end
41
49
 
@@ -11,814 +11,6 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
-
15
- require 'datastreams/fits_datastream'
16
- require 'datastreams/generic_file_rdf_datastream'
17
- require 'datastreams/properties_datastream'
18
- require 'datastreams/paranoid_rights_datastream'
19
- require 'datastreams/file_content_datastream'
20
-
21
14
  class GenericFile < ActiveFedora::Base
22
- include ActiveModel::Validations::HelperMethods
23
- include ActiveFedora::Validations
24
- include Hydra::ModelMixins::CommonMetadata
25
- include Hydra::ModelMixins::RightsMetadata
26
- include Sufia::ModelMethods
27
- include Sufia::Noid
28
-
29
- @@FIELD_LABEL_MAP = {"based_near"=>"Location", 'description'=>"Abstract or Summary", 'tag'=>"Keyword", 'date_created'=>"Date Created", 'related_url'=>"Related URL"}
30
-
31
- has_metadata :name => "characterization", :type => FitsDatastream
32
- has_metadata :name => "descMetadata", :type => GenericFileRdfDatastream
33
- has_metadata :name => "properties", :type => PropertiesDatastream
34
- has_metadata :name => "rightsMetadata", :type => ParanoidRightsDatastream
35
- has_file_datastream :name => "content", :type => FileContentDatastream
36
- has_file_datastream :name => "thumbnail", :type => FileContentDatastream
37
-
38
- belongs_to :batch, :property => :is_part_of
39
-
40
- delegate_to :properties, [:relative_path, :depositor], :unique => true
41
- delegate_to :descMetadata, [:date_uploaded, :date_modified], :unique => true
42
- delegate_to :descMetadata, [:related_url, :based_near, :part_of, :creator,
43
- :contributor, :title, :tag, :description, :rights,
44
- :publisher, :date_created, :subject, :format,
45
- :resource_type, :identifier, :language]
46
- delegate :mime_type, :to => :characterization, :unique => true
47
- delegate_to :characterization, [:format_label, :file_size, :last_modified,
48
- :filename, :original_checksum, :rights_basis,
49
- :copyright_basis, :copyright_note,
50
- :well_formed, :valid, :status_message,
51
- :file_title, :file_author, :page_count,
52
- :file_language, :word_count, :character_count,
53
- :paragraph_count, :line_count, :table_count,
54
- :graphics_count, :byte_order, :compression,
55
- :width, :height, :color_space, :profile_name,
56
- :profile_version, :orientation, :color_map,
57
- :image_producer, :capture_device,
58
- :scanning_software, :exif_version,
59
- :gps_timestamp, :latitude, :longitude,
60
- :character_set, :markup_basis,
61
- :markup_language, :duration, :bit_depth,
62
- :sample_rate, :channels, :data_format, :offset]
63
-
64
- around_save :characterize_if_changed, :retry_warming
65
- validate :paranoid_permissions
66
-
67
-
68
- NO_RUNS = 999
69
-
70
- #make sure the terms of service is present and set to 1 before saving
71
- # note GenericFile.create will no longer save a GenericFile as the terms_of_service will not be set
72
- terms_of_service = nil
73
- validates_acceptance_of :terms_of_service, :allow_nil => false
74
-
75
- # set the terms of service on create so an empty generic file can be created
76
- #before_validation(:on => :create) do
77
- # logger.info "!!!! Before create !!!!"
78
- # self.terms_of_service = '1'
79
- #end
80
-
81
- def self.get_label(key)
82
- label = @@FIELD_LABEL_MAP[key]
83
- puts "label = #{label}"
84
- label = key.gsub('_',' ').titleize if label.blank?
85
- return label
86
- end
87
-
88
- def persistent_url
89
- "#{Sufia::Engine.config.persistent_hostpath}#{noid}"
90
- end
91
-
92
- def paranoid_permissions
93
- # let the rightsMetadata ds make this determination
94
- # - the object instance is passed in for easier access to the props ds
95
- rightsMetadata.validate(self)
96
- end
97
-
98
- ## Updates those permissions that are provided to it. Does not replace any permissions unless they are provided
99
- def permissions=(params)
100
- perm_hash = permission_hash
101
- params[:new_user_name].each { |name, access| perm_hash['person'][name] = access } if params[:new_user_name].present?
102
- params[:new_group_name].each { |name, access| perm_hash['group'][name] = access } if params[:new_group_name].present?
103
-
104
- params[:user].each { |name, access| perm_hash['person'][name] = access} if params[:user]
105
- params[:group].each { |name, access| perm_hash['group'][name] = access} if params[:group]
106
- rightsMetadata.update_permissions(perm_hash)
107
- end
108
-
109
- def retry_warming
110
- save_tries = 0
111
- conflict_tries = 0
112
- begin
113
- yield
114
- rescue RSolr::Error::Http => error
115
- save_tries += 1
116
- logger.warn "Retry Solr caught RSOLR error on #{self.pid}: #{error.inspect}"
117
- # fail for good if the tries is greater than 3
118
- rescue_action_without_handler(error) if save_tries >=3
119
- sleep 0.01
120
- retry
121
- rescue ActiveResource::ResourceConflict => error
122
- conflict_tries += 1
123
- logger.warn "Retry caught Active Resource Conflict #{self.pid}: #{error.inspect}"
124
- rescue_action_without_handler(error) if conflict_tries >=10
125
- sleep 0.01
126
- retry
127
- rescue =>error
128
- if (error.to_s.downcase.include? "conflict")
129
- conflict_tries += 1
130
- logger.warn "Retry caught Active Resource Conflict #{self.pid}: #{error.inspect}"
131
- rescue_action_without_handler(error) if conflict_tries >=10
132
- sleep 0.01
133
- retry
134
- else
135
- rescue_action_without_handler(error)
136
- end
137
-
138
- end
139
- end
140
-
141
- def characterize_if_changed
142
- content_changed = self.content.changed?
143
- yield
144
- #logger.debug "DOING CHARACTERIZE ON #{self.pid}"
145
- begin
146
- Resque.enqueue(CharacterizeJob, self.pid) if content_changed
147
- rescue Redis::CannotConnectError
148
- logger.error "Redis is down!"
149
- end
150
- end
151
-
152
- ## Extract the metadata from the content datastream and record it in the characterization datastream
153
- def characterize
154
- self.characterization.content = self.content.extract_metadata
155
- self.append_metadata
156
- self.filename = self.label
157
- self.terms_of_service = '1'
158
- save unless self.new_object?
159
- end
160
-
161
- def related_files
162
- relateds = begin
163
- self.batch.generic_files
164
- rescue NoMethodError => e
165
- #batch is nil
166
- batch_id = self.object_relations["isPartOf"].first || self.object_relations[:is_part_of].first
167
- return [] if batch_id.nil?
168
- self.class.find(:is_part_of_s => batch_id)
169
- end
170
- relateds.reject { |gf| gf.pid == self.pid }
171
- end
172
-
173
- # Create thumbnail requires that the characterization has already been run (so mime_type, width and height is available)
174
- # and that the object is already has a pid set
175
- def create_thumbnail
176
- return if self.content.content.nil?
177
- if ["application/pdf"].include? self.mime_type
178
- create_pdf_thumbnail
179
- elsif ["image/png","image/jpeg", "image/gif"].include? self.mime_type
180
- create_image_thumbnail
181
- # TODO: if we can figure out how to do video (ffmpeg?)
182
- #elsif ["video/mpeg", "video/mp4"].include? self.mime_type
183
- end
184
- end
185
-
186
- # redefine find so that it sets the terms of service
187
- def self.find(args, opts={})
188
- gf = super
189
- # use the field type to see if the return will be one item or multiple
190
- if args.is_a? String
191
- gf.terms_of_service = '1'
192
- elsif gf.respond_to? :each
193
- gf.each {|f| f.terms_of_service = '1'}
194
- end
195
- return gf
196
- end
197
-
198
- def create_pdf_thumbnail
199
- retryCnt = 0
200
- stat = false;
201
- for retryCnt in 1..3
202
- begin
203
- pdf = Magick::ImageList.new
204
- pdf.from_blob(content.content)
205
- first = pdf.to_a[0]
206
- first.format = "PNG"
207
- thumb = first.scale(338, 493)
208
- self.thumbnail.content = thumb.to_blob { self.format = "PNG" }
209
- #logger.debug "Has the content changed before saving? #{self.content.changed?}"
210
- self.terms_of_service = '1'
211
- stat = self.save
212
- break
213
- rescue => e
214
- logger.warn "Rescued an error #{e.inspect} retry count = #{retryCnt}"
215
- sleep 1
216
- end
217
- end
218
- return stat
219
- end
220
-
221
- def create_image_thumbnail
222
- img = Magick::ImageList.new
223
- img.from_blob(content.content)
224
- # horizontal img
225
- height = self.height.first.to_i
226
- width = self.width.first.to_i
227
- scale = height / width
228
- if width > height
229
- if width > 150 and height > 105
230
- thumb = img.scale(150, height/scale)
231
- else
232
- thumb = img.scale(width, height)
233
- end
234
- # vertical img
235
- else
236
- if width > 150 and height > 200
237
- thumb = img.scale(150*scale, 200)
238
- else
239
- thumb = img.scale(width, height)
240
- end
241
- end
242
- self.thumbnail.content = thumb.to_blob
243
- self.terms_of_service = '1'
244
- #logger.debug "Has the content before saving? #{self.content.changed?}"
245
- self.save
246
- end
247
-
248
- def append_metadata
249
- terms = self.characterization_terms
250
- Sufia::Engine.config.fits_to_desc_mapping.each_pair do |k, v|
251
- if terms.has_key?(k)
252
- # coerce to array to remove a conditional
253
- terms[k] = [terms[k]] unless terms[k].is_a? Array
254
- terms[k].each do |term_value|
255
- proxy_term = self.send(v)
256
- if proxy_term.kind_of?(Array)
257
- proxy_term << term_value unless proxy_term.include?(term_value)
258
- else
259
- # these are single-valued terms which cannot be appended to
260
- self.send("#{v}=", term_value)
261
- end
262
- end
263
- end
264
- end
265
- end
266
-
267
- def set_visibility(params)
268
- # only set explicit permissions
269
- if params[:visibility] == "open"
270
- self.datastreams["rightsMetadata"].permissions({:group=>"public"}, "read")
271
- elsif params[:visibility] == "psu"
272
- self.datastreams["rightsMetadata"].permissions({:group=>"registered"}, "read")
273
- self.datastreams["rightsMetadata"].permissions({:group=>"public"}, "none")
274
- elsif params[:visibility] == "restricted"
275
- self.datastreams["rightsMetadata"].permissions({:group=>"registered"}, "none")
276
- self.datastreams["rightsMetadata"].permissions({:group=>"public"}, "none")
277
- #params[:generic_file][:permissions][:group][:public] = "none"
278
- #params[:generic_file][:permissions][:group][:registered] = "none"
279
- end
280
- end
281
-
282
- def to_solr(solr_doc={}, opts={})
283
- super(solr_doc, opts)
284
- solr_doc["label_t"] = self.label
285
- solr_doc["noid_s"] = noid
286
- solr_doc["file_format_t"] = file_format
287
- solr_doc["file_format_facet"] = solr_doc["file_format_t"]
288
- # remap dates as a valid xml date not to_s
289
- solr_doc['generic_file__date_uploaded_dt'] = Time.parse(date_uploaded).utc.to_s.sub(' ','T').sub(' UTC','Z') rescue Time.new(date_uploaded).utc.to_s.sub(' ','T').sub(' UTC','Z') unless date_uploaded.blank?
290
- solr_doc['generic_file__date_modified_dt'] = Time.parse(date_modified).utc.to_s.sub(' ','T').sub(' UTC','Z') rescue Time.new(date_modified).utc.to_s.sub(' ','T').sub(' UTC','Z') unless date_modified.blank?
291
- return solr_doc
292
- end
293
-
294
- def file_format
295
- return nil if self.mime_type.blank? and self.format_label.blank?
296
- return self.mime_type.split('/')[1]+ " ("+self.format_label.join(", ")+")" unless self.mime_type.blank? or self.format_label.blank?
297
- return self.mime_type.split('/')[1] unless self.mime_type.blank?
298
- return self.format_label
299
- end
300
-
301
- # Redefine this for more intuitive keys in Redis
302
- def to_param
303
- noid
304
- end
305
-
306
- def label=(new_label)
307
- @inner_object.label = new_label
308
- if self.title.empty?
309
- self.title = new_label
310
- end
311
- end
312
-
313
- def to_jq_upload
314
- return {
315
- "name" => self.title,
316
- "size" => self.file_size,
317
- "url" => "/files/#{noid}",
318
- "thumbnail_url" => self.pid,
319
- "delete_url" => "deleteme", # generic_file_path(:id => id),
320
- "delete_type" => "DELETE"
321
- }
322
- end
323
-
324
- def get_terms
325
- terms = []
326
- self.descMetadata.class.config[:predicate_mapping].each do |uri, mappings|
327
- new_terms = mappings.keys.map(&:to_s).select do |term|
328
- term.start_with? "generic_file__" and !['type', 'behaviors'].include? term.split('__').last
329
- end
330
- terms.concat(new_terms)
331
- end
332
- terms
333
- end
334
-
335
- def get_values
336
- terms = get_terms
337
- values = {}
338
- terms.each do |t|
339
- next if t.empty?
340
- key = t.to_s.split("generic_file__").last
341
- next if ['part_of', 'date_modified', 'date_uploaded', 'format'].include?(key)
342
- values[key] = self.send(key) if self.respond_to?(key)
343
- end
344
- return values
345
- end
346
-
347
- def characterization_terms
348
- h = {}
349
- self.characterization.class.terminology.terms.each_pair do |k, v|
350
- next unless v.respond_to? :proxied_term
351
- term = v.proxied_term
352
- begin
353
- value = self.send(term.name)
354
- h[term.name] = value unless value.empty?
355
- rescue NoMethodError
356
- next
357
- end
358
- end
359
- h
360
- end
361
-
362
- # MIME: 'application/x-endnote-refer'
363
- def export_as_endnote
364
- end_note_format = {
365
- '%T' => [:title, lambda { |x| x.first }],
366
- '%Q' => [:title, lambda { |x| x.drop(1) }],
367
- '%A' => [:creator],
368
- '%C' => [:publication_place],
369
- '%D' => [:date_created],
370
- '%8' => [:date_uploaded],
371
- '%E' => [:contributor],
372
- '%I' => [:publisher],
373
- '%J' => [:series_title],
374
- '%@' => [:isbn],
375
- '%U' => [:related_url],
376
- '%7' => [:edition_statement],
377
- '%R' => [:persistent_url],
378
- '%X' => [:description],
379
- '%G' => [:language],
380
- '%[' => [:date_modified],
381
- '%9' => [:resource_type],
382
- '%~' => Application.config.application_name,
383
- '%W' => 'Penn State University'
384
- }
385
- text = []
386
- text << "%0 GenericFile"
387
- end_note_format.each do |endnote_key, mapping|
388
- if mapping.is_a? String
389
- values = [mapping]
390
- else
391
- values = self.send(mapping[0]) if self.respond_to? mapping[0]
392
- values = mapping[1].call(values) if mapping.length == 2
393
- values = [values] unless values.is_a? Array
394
- end
395
- next if values.empty? or values.first.nil?
396
- spaced_values = values.join("; ")
397
- text << "#{endnote_key} #{spaced_values}"
398
- end
399
- return text.join("\n")
400
- end
401
-
402
- # MIME type: 'application/x-openurl-ctx-kev'
403
- def export_as_openurl_ctx_kev
404
- export_text = []
405
- export_text << "url_ver=Z39.88-2004&ctx_ver=Z39.88-2004&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3Adc&rfr_id=info%3Asid%2Fblacklight.rubyforge.org%3Agenerator"
406
- field_map = {
407
- :title => 'title',
408
- :creator => 'creator',
409
- :subject => 'subject',
410
- :description => 'description',
411
- :publisher => 'publisher',
412
- :contributor => 'contributor',
413
- :date_created => 'date',
414
- :resource_type => 'format',
415
- :identifier => 'identifier',
416
- :language => 'language',
417
- :tag => 'relation',
418
- :based_near => 'coverage',
419
- :rights => 'rights'
420
- }
421
- field_map.each do |element, kev|
422
- values = self.send(element)
423
- next if values.empty? or values.first.nil?
424
- values.each do |value|
425
- export_text << "rft.#{kev}=#{CGI::escape(value)}"
426
- end
427
- end
428
- export_text.join('&') unless export_text.blank?
429
- end
430
-
431
- def export_as_apa_citation
432
- text = ''
433
- authors_list = []
434
- authors_list_final = []
435
-
436
- #setup formatted author list
437
- authors = get_author_list
438
- authors.each do |author|
439
- next if author.blank?
440
- authors_list.push(abbreviate_name(author))
441
- end
442
- authors_list.each do |author|
443
- if author == authors_list.first #first
444
- authors_list_final.push(author.strip)
445
- elsif author == authors_list.last #last
446
- authors_list_final.push(", &amp; " + author.strip)
447
- else #all others
448
- authors_list_final.push(", " + author.strip)
449
- end
450
- end
451
- text << authors_list_final.join
452
- unless text.blank?
453
- if text[-1,1] != "."
454
- text << ". "
455
- else
456
- text << " "
457
- end
458
- end
459
- # Get Pub Date
460
- text << "(" + setup_pub_date + "). " unless setup_pub_date.nil?
461
-
462
- # setup title info
463
- title_info = setup_title_info
464
- text << "<i>" + title_info + "</i> " unless title_info.nil?
465
-
466
- # Publisher info
467
- text << setup_pub_info unless setup_pub_info.nil?
468
- unless text.blank?
469
- if text[-1,1] != "."
470
- text += "."
471
- end
472
- end
473
- text.html_safe
474
- end
475
-
476
- def export_as_mla_citation
477
- text = ''
478
- authors_final = []
479
-
480
- #setup formatted author list
481
- authors = get_author_list
482
-
483
- if authors.length < 4
484
- authors.each do |author|
485
- if author == authors.first #first
486
- authors_final.push(author)
487
- elsif author == authors.last #last
488
- authors_final.push(", and " + name_reverse(author) + ".")
489
- else #all others
490
- authors_final.push(", " + name_reverse(author))
491
- end
492
- end
493
- text << authors_final.join
494
- unless text.blank?
495
- if text[-1,1] != "."
496
- text << ". "
497
- else
498
- text << " "
499
- end
500
- end
501
- else
502
- text << authors.first + ", et al. "
503
- end
504
- # setup title
505
- title_info = setup_title_info
506
- text << "<i>" + mla_citation_title(title_info) + "</i> " unless title.blank?
507
-
508
- # Publication
509
- text << setup_pub_info + ", " unless setup_pub_info.nil?
510
-
511
- # Get Pub Date
512
- text << setup_pub_date unless setup_pub_date.nil?
513
- if text[-1,1] != "."
514
- text << "." unless text.blank?
515
- end
516
- text.html_safe
517
- end
518
-
519
- def export_as_chicago_citation
520
- author_text = ""
521
- authors = get_all_authors
522
- unless authors.blank?
523
- if authors.length > 10
524
- authors.each_with_index do |author, index|
525
- if index < 7
526
- if index == 0
527
- author_text << "#{author}"
528
- if author.ends_with?(",")
529
- author_text << " "
530
- else
531
- author_text << ", "
532
- end
533
- else
534
- author_text << "#{name_reverse(author)}, "
535
- end
536
- end
537
- end
538
- author_text << " et al."
539
- elsif authors.length > 1
540
- authors.each_with_index do |author,index|
541
- if index == 0
542
- author_text << "#{author}"
543
- if author.ends_with?(",")
544
- author_text << " "
545
- else
546
- author_text << ", "
547
- end
548
- elsif index + 1 == authors.length
549
- author_text << "and #{name_reverse(author)}."
550
- else
551
- author_text << "#{name_reverse(author)}, "
552
- end
553
- end
554
- else
555
- author_text << authors.first
556
- end
557
- end
558
- title_info = ""
559
- title_info << citation_title(clean_end_punctuation(CGI::escapeHTML(title.first)).strip) unless title.blank?
560
-
561
- pub_info = ""
562
- place = self.based_near.first
563
- publisher = self.publisher.first
564
- unless place.blank?
565
- place = CGI::escapeHTML(place)
566
- pub_info << place
567
- pub_info << ": " unless publisher.blank?
568
- end
569
- unless publisher.blank?
570
- publisher = CGI::escapeHTML(publisher)
571
- pub_info << publisher
572
- pub_info << ", " unless setup_pub_date.nil?
573
- end
574
- unless setup_pub_date.nil?
575
- pub_info << setup_pub_date
576
- end
577
-
578
- citation = ""
579
- citation << "#{author_text} " unless author_text.blank?
580
- citation << "<i>#{title_info}.</i> " unless title_info.blank?
581
- citation << "#{pub_info}." unless pub_info.blank?
582
- citation.html_safe
583
- end
584
-
585
- def logs(dsid)
586
- ChecksumAuditLog.where(:dsid=>dsid, :pid=>self.pid).order('created_at desc, id desc')
587
- end
588
-
589
- def audit!
590
- audit(true)
591
- end
592
-
593
- def audit_stat!
594
- audit_stat(true)
595
- end
596
-
597
- def audit_stat(force = false)
598
- logs = audit(force)
599
- audit_results = logs.collect { |result| result["pass"] }
600
-
601
- # check how many non runs we had
602
- non_runs =audit_results.reduce(0) { |sum, value| (value == NO_RUNS) ? sum = sum+1 : sum }
603
- if (non_runs == 0)
604
- result =audit_results.reduce(true) { |sum, value| sum && value }
605
- return result
606
- elsif (non_runs < audit_results.length)
607
- result =audit_results.reduce(true) { |sum, value| (value == NO_RUNS) ? sum : sum && value }
608
- return 'Some audits have not been run, but the ones run were '+ ((result)? 'passing' : 'failing') + '.'
609
- else
610
- return 'Audits have not yet been run on this file.'
611
- end
612
- end
613
-
614
- def audit(force = false)
615
- logs = []
616
- self.per_version do |ver|
617
- logs << GenericFile.audit(ver, force)
618
- end
619
- logs
620
- end
621
-
622
- def per_version(&block)
623
- self.datastreams.each do |dsid, ds|
624
- ds.versions.each do |ver|
625
- block.call(ver)
626
- end
627
- end
628
- end
629
-
630
- def self.audit!(version)
631
- GenericFile.audit(version, true)
632
- end
633
-
634
- def self.audit(version, force = false)
635
- #logger.debug "***AUDIT*** log for #{version.inspect}"
636
- latest_audit = self.find(version.pid).logs(version.dsid).first
637
- unless force
638
- return latest_audit unless GenericFile.needs_audit?(version, latest_audit)
639
- end
640
- begin
641
- Resque.enqueue(AuditJob, version.pid, version.dsid, version.versionID)
642
- rescue Redis::CannotConnectError
643
- logger.error "Redis is down!"
644
- end
645
-
646
- # run the find just incase the job has finished already
647
- latest_audit = self.find(version.pid).logs(version.dsid).first
648
- latest_audit = ChecksumAuditLog.new(:pass=>NO_RUNS, :pid=>version.pid, :dsid=>version.dsid, :version=>version.versionID) unless latest_audit
649
- return latest_audit
650
- end
651
-
652
- def self.needs_audit?(version, latest_audit)
653
- if latest_audit and latest_audit.updated_at
654
- #logger.debug "***AUDIT*** last audit = #{latest_audit.updated_at.to_date}"
655
- days_since_last_audit = (DateTime.now - latest_audit.updated_at.to_date).to_i
656
- #logger.debug "***AUDIT*** days since last audit: #{days_since_last_audit}"
657
- if days_since_last_audit < Sufia::Engine.config.max_days_between_audits
658
- #logger.debug "***AUDIT*** No audit needed for #{version.pid} #{version.versionID} (#{latest_audit.updated_at})"
659
- return false
660
- end
661
- else
662
- logger.warn "***AUDIT*** problem with audit log! Latest Audit is not nil, but updated_at is not set #{latest_audit}" unless latest_audit.nil?
663
- end
664
- #logger.info "***AUDIT*** Audit needed for #{version.pid} #{version.versionID}"
665
- return true
666
- end
667
-
668
- def self.audit_everything(force = false)
669
- GenericFile.find(:all, :rows => GenericFile.count).each do |gf|
670
- gf.per_version do |ver|
671
- GenericFile.audit(ver, force)
672
- end
673
- end
674
- end
675
-
676
- def self.audit_everything!
677
- GenericFile.audit_everything(true)
678
- end
679
-
680
- def self.run_audit(version)
681
- if version.dsChecksumValid
682
- #logger.info "***AUDIT*** Audit passed for #{version.pid} #{version.versionID}"
683
- passing = 1
684
- ChecksumAuditLog.prune_history(version)
685
- else
686
- logger.warn "***AUDIT*** Audit failed for #{version.pid} #{version.versionID}"
687
- passing = 0
688
- end
689
- check = ChecksumAuditLog.create!(:pass=>passing, :pid=>version.pid,
690
- :dsid=>version.dsid, :version=>version.versionID)
691
- return check
692
- end
693
-
694
- # Is this file in the middle of being processed by a batch?
695
- def processing?
696
- return false if self.batch.blank?
697
- return false if !self.batch.methods.include? :status
698
- return (!self.batch.status.empty?) && (self.batch.status.count == 1) && (self.batch.status[0] == "processing")
699
- end
700
-
701
- private
702
-
703
- def permission_hash
704
- old_perms = self.permissions
705
- user_perms = {}
706
- old_perms.select{|r| r[:type] == 'user'}.each do |r|
707
- user_perms[r[:name]] = r[:access]
708
- end
709
- user_perms
710
- group_perms = {}
711
- old_perms.select{|r| r[:type] == 'group'}.each do |r|
712
- group_perms[r[:name]] = r[:access]
713
- end
714
- {'person'=>user_perms, 'group'=>group_perms}
715
- end
716
-
717
- def setup_pub_date
718
- first_date = self.date_created.first
719
- unless first_date.blank?
720
- first_date = CGI::escapeHTML(first_date)
721
- date_value = first_date.gsub(/[^0-9|n\.d\.]/, "")[0,4]
722
- return nil if date_value.nil?
723
- end
724
- clean_end_punctuation(date_value) if date_value
725
- end
726
-
727
- def setup_pub_info
728
- text = ''
729
- place = self.based_near.first
730
- publisher = self.publisher.first
731
- unless place.blank?
732
- place = CGI::escapeHTML(place)
733
- text << place
734
- text << ": " unless publisher.blank?
735
- end
736
- unless publisher.blank?
737
- publisher = CGI::escapeHTML(publisher)
738
- text << publisher
739
- end
740
- return nil if text.strip.blank?
741
- clean_end_punctuation(text.strip)
742
- end
743
-
744
- def mla_citation_title(text)
745
- no_upcase = ["a","an","and","but","by","for","it","of","the","to","with"]
746
- new_text = []
747
- word_parts = text.split(" ")
748
- word_parts.each do |w|
749
- if !no_upcase.include? w
750
- new_text.push(w.capitalize)
751
- else
752
- new_text.push(w)
753
- end
754
- end
755
- new_text.join(" ")
756
- end
757
-
758
- def citation_title(title_text)
759
- prepositions = ["a","about","across","an","and","before","but","by","for","it","of","the","to","with","without"]
760
- new_text = []
761
- title_text.split(" ").each_with_index do |word,index|
762
- if (index == 0 and word != word.upcase) or (word.length > 1 and word != word.upcase and !prepositions.include?(word))
763
- # the split("-") will handle the capitalization of hyphenated words
764
- new_text << word.split("-").map!{|w| w.capitalize }.join("-")
765
- else
766
- new_text << word
767
- end
768
- end
769
- new_text.join(" ")
770
- end
771
-
772
- def setup_title_info
773
- text = ''
774
- title = self.title.first
775
- unless title.blank?
776
- title = CGI::escapeHTML(title)
777
- title_info = clean_end_punctuation(title.strip)
778
- text << title_info
779
- end
780
-
781
- return nil if text.strip.blank?
782
- clean_end_punctuation(text.strip) + "."
783
- end
784
-
785
- def clean_end_punctuation(text)
786
- if [".",",",":",";","/"].include? text[-1,1]
787
- return text[0,text.length-1]
788
- end
789
- text
790
- end
791
-
792
- def get_author_list
793
- self.creator.map { |author| clean_end_punctuation(CGI::escapeHTML(author)) }.uniq
794
- end
795
-
796
- def get_all_authors
797
- authors = self.creator
798
- return authors.empty? ? nil : authors.map { |author| CGI::escapeHTML(author) }
799
- end
800
-
801
- def abbreviate_name(name)
802
- abbreviated_name = ''
803
- name = name.join('') if name.is_a? Array
804
- # make sure we handle "Cher" correctly
805
- return name if !name.include?(' ') and !name.include?(',')
806
- surnames_first = name.include?(',')
807
- delimiter = surnames_first ? ', ' : ' '
808
- name_segments = name.split(delimiter)
809
- given_names = surnames_first ? name_segments.last.split(' ') : name_segments.first.split(' ')
810
- surnames = surnames_first ? name_segments.first.split(' ') : name_segments.last.split(' ')
811
- abbreviated_name << surnames.join(' ')
812
- abbreviated_name << ', '
813
- abbreviated_name << given_names.map { |n| "#{n[0]}." }.join if given_names.is_a? Array
814
- abbreviated_name << "#{given_names[0]}." if given_names.is_a? String
815
- abbreviated_name
816
- end
817
-
818
- def name_reverse(name)
819
- name = clean_end_punctuation(name)
820
- return name unless name =~ /,/
821
- temp_name = name.split(", ")
822
- return temp_name.last + " " + temp_name.first
823
- end
15
+ include Sufia::GenericFile
824
16
  end