sufia-models 5.0.0.beta1 → 5.0.0.rc1

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/app/actors/sufia/generic_file/actor.rb +10 -7
  3. data/app/jobs/active_fedora_pid_based_job.rb +3 -2
  4. data/app/jobs/audit_job.rb +31 -28
  5. data/app/jobs/batch_update_job.rb +8 -9
  6. data/app/jobs/import_url_job.rb +2 -2
  7. data/app/models/batch.rb +12 -11
  8. data/app/models/checksum_audit_log.rb +8 -7
  9. data/app/models/concerns/sufia/ability.rb +6 -4
  10. data/app/models/concerns/sufia/collection.rb +5 -4
  11. data/app/models/concerns/sufia/file_stat_utils.rb +3 -3
  12. data/app/models/concerns/sufia/generic_file.rb +14 -16
  13. data/app/models/concerns/sufia/generic_file/audit.rb +31 -50
  14. data/app/models/concerns/sufia/generic_file/characterization.rb +3 -3
  15. data/app/models/concerns/sufia/generic_file/derivatives.rb +5 -5
  16. data/app/models/concerns/sufia/generic_file/full_text_indexing.rb +2 -2
  17. data/app/models/concerns/sufia/generic_file/metadata.rb +11 -82
  18. data/app/models/concerns/sufia/generic_file/proxy_deposit.rb +3 -12
  19. data/app/models/concerns/sufia/generic_file/reload_on_save.rb +18 -0
  20. data/app/models/concerns/sufia/generic_file/versions.rb +4 -1
  21. data/app/models/concerns/sufia/generic_file/web_form.rb +6 -13
  22. data/app/models/concerns/sufia/model_methods.rb +9 -11
  23. data/app/models/concerns/sufia/properties_datastream_behavior.rb +32 -0
  24. data/app/models/concerns/sufia/user.rb +33 -11
  25. data/app/models/concerns/sufia/user_usage_stats.rb +15 -0
  26. data/app/models/datastreams/batch_rdf_datastream.rb +6 -0
  27. data/app/models/datastreams/file_content_datastream.rb +1 -1
  28. data/app/models/datastreams/fits_datastream.rb +1 -1
  29. data/app/models/datastreams/generic_file_rdf_datastream.rb +69 -0
  30. data/app/models/datastreams/paranoid_rights_datastream.rb +22 -0
  31. data/app/models/datastreams/properties_datastream.rb +4 -0
  32. data/app/models/file_download_stat.rb +2 -2
  33. data/app/models/file_usage.rb +9 -5
  34. data/app/models/file_view_stat.rb +2 -2
  35. data/app/models/local_authority.rb +2 -2
  36. data/app/models/proxy_deposit_request.rb +1 -1
  37. data/app/models/sufia/orcid_validator.rb +8 -0
  38. data/app/models/user_stat.rb +2 -0
  39. data/app/services/sufia/id_service.rb +5 -5
  40. data/app/services/sufia/noid.rb +7 -10
  41. data/lib/generators/sufia/models/abstract_migration_generator.rb +30 -0
  42. data/lib/generators/sufia/models/cached_stats_generator.rb +2 -31
  43. data/lib/generators/sufia/models/install_generator.rb +11 -31
  44. data/lib/generators/sufia/models/orcid_field_generator.rb +19 -0
  45. data/lib/generators/sufia/models/proxies_generator.rb +2 -31
  46. data/lib/generators/sufia/models/templates/config/sufia.rb +3 -10
  47. data/lib/generators/sufia/models/templates/migrations/add_orcid_to_users.rb +5 -0
  48. data/lib/generators/sufia/models/templates/migrations/create_user_stats.rb +19 -0
  49. data/lib/generators/sufia/models/upgrade400_generator.rb +2 -33
  50. data/lib/generators/sufia/models/user_stats_generator.rb +31 -0
  51. data/lib/sufia/models/engine.rb +4 -13
  52. data/lib/sufia/models/file_content/versions.rb +8 -12
  53. data/lib/sufia/models/stats/user_stat_importer.rb +89 -0
  54. data/lib/sufia/models/version.rb +1 -1
  55. data/lib/sufia/permissions/writable.rb +16 -34
  56. data/lib/tasks/stats_tasks.rake +12 -0
  57. data/sufia-models.gemspec +2 -4
  58. metadata +78 -90
@@ -0,0 +1,19 @@
1
+ require_relative 'abstract_migration_generator'
2
+
3
+ class Sufia::Models::OrcidFieldGenerator < Sufia::Models::AbstractMigrationGenerator
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ desc """
7
+ This generator adds a field to hold users' ORCIDs to your application:
8
+ 1. Creates a database migration if they do not exist in /db/migrate
9
+ """
10
+
11
+ def banner
12
+ say_status("warning", "ADDING ORCID FIELD TO USER MODEL", :yellow)
13
+ end
14
+
15
+ # Setup the database migration
16
+ def copy_migrations
17
+ better_migration_template 'add_orcid_to_users.rb'
18
+ end
19
+ end
@@ -1,30 +1,12 @@
1
- # -*- encoding : utf-8 -*-
2
- require 'rails/generators'
3
- require 'rails/generators/migration'
4
-
5
- class Sufia::Models::ProxiesGenerator < Rails::Generators::Base
6
- include Rails::Generators::Migration
1
+ require_relative 'abstract_migration_generator'
7
2
 
3
+ class Sufia::Models::ProxiesGenerator < Sufia::Models::AbstractMigrationGenerator
8
4
  source_root File.expand_path('../templates', __FILE__)
9
5
 
10
6
  desc """
11
7
  This generator adds proxies and transfers to your application:
12
8
  1. Creates several database migrations if they do not exist in /db/migrate
13
9
  """
14
- # Implement the required interface for Rails::Generators::Migration.
15
- # taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
16
- def self.next_migration_number(path)
17
- if @prev_migration_nr
18
- @prev_migration_nr += 1
19
- else
20
- if last_migration = Dir[File.join(path, '*.rb')].sort.last
21
- @prev_migration_nr = last_migration.sub(File.join(path, '/'), '').to_i + 1
22
- else
23
- @prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
24
- end
25
- end
26
- @prev_migration_nr.to_s
27
- end
28
10
 
29
11
  def banner
30
12
  say_status("warning", "ADDING PROXY/TRANSFER-RELATED SUFIA MODELS", :yellow)
@@ -32,7 +14,6 @@ This generator adds proxies and transfers to your application:
32
14
 
33
15
  # Setup the database migrations
34
16
  def copy_migrations
35
- # Can't get this any more DRY, because we need this order.
36
17
  [
37
18
  'create_proxy_deposit_rights.rb',
38
19
  'create_proxy_deposit_requests.rb'
@@ -40,14 +21,4 @@ This generator adds proxies and transfers to your application:
40
21
  better_migration_template file
41
22
  end
42
23
  end
43
-
44
- private
45
-
46
- def better_migration_template(file)
47
- begin
48
- migration_template "migrations/#{file}", "db/migrate/#{file}"
49
- rescue Rails::Generators::Error => e
50
- say_status("warning", e.message, :yellow)
51
- end
52
- end
53
24
  end
@@ -93,6 +93,9 @@ Sufia.config do |config|
93
93
  # Specify a Google Analytics tracking ID to gather usage statistics
94
94
  # config.google_analytics_id = 'UA-99999999-1'
95
95
 
96
+ # Specify a date you wish to start collecting Google Analytic statistics for.
97
+ # config.analytic_start_date = DateTime.new(2014,9,10)
98
+
96
99
  # Where to store tempfiles, leave blank for the system temp directory (e.g. /tmp)
97
100
  # config.temp_file_base = '/home/developer1'
98
101
 
@@ -108,16 +111,6 @@ Sufia.config do |config|
108
111
  # Specify how many seconds back from the current time that we should show by default of the user's activity on the user's dashboard
109
112
  # config.activity_to_show_default_seconds_since_now = 24*60*60
110
113
 
111
- # Specify a date you wish to start collecting Google Analytic statistics for.
112
- # Leaving it blank will set the start date to when ever the file was uploaded by
113
- # NOTE: if you have always sent analytics to GA for downloads and page views leave this commented out
114
- # config.analytic_start_date = DateTime.new(2014,9,10)
115
- #
116
- # Method of converting pids into URIs for storage in Fedora
117
- # config.translate_uri_to_id = lambda { |uri| uri.to_s.split('/')[-1] }
118
- # config.translate_id_to_uri = lambda { |id|
119
- # "#{ActiveFedora.fedora.host}#{ActiveFedora.fedora.base_path}/#{Sufia::Noid.treeify(id)}" }
120
-
121
114
  # If browse-everything has been configured, load the configs. Otherwise, set to nil.
122
115
  begin
123
116
  if defined? BrowseEverything
@@ -0,0 +1,5 @@
1
+ class AddOrcidToUsers < ActiveRecord::Migration
2
+ def change
3
+ add_column :users, :orcid, :string
4
+ end
5
+ end
@@ -0,0 +1,19 @@
1
+ class CreateUserStats < ActiveRecord::Migration
2
+ def change
3
+ create_table :user_stats do |t|
4
+ t.integer :user_id
5
+ t.datetime :date
6
+ t.integer :file_views
7
+ t.integer :file_downloads
8
+
9
+ t.timestamps
10
+ end
11
+
12
+ add_column :file_view_stats, :user_id, :integer
13
+ add_column :file_download_stats, :user_id, :integer
14
+
15
+ add_index :user_stats, :user_id
16
+ add_index :file_view_stats, :user_id
17
+ add_index :file_download_stats, :user_id
18
+ end
19
+ end
@@ -1,13 +1,8 @@
1
- # -*- encoding : utf-8 -*-
2
- require 'rails/generators'
3
- require 'rails/generators/migration'
4
-
5
- class Sufia::Models::Upgrade400Generator < Rails::Generators::Base
6
- include Rails::Generators::Migration
1
+ require_relative 'abstract_migration_generator'
7
2
 
3
+ class Sufia::Models::Upgrade400Generator < Sufia::Models::AbstractMigrationGenerator
8
4
  source_root File.expand_path('../templates', __FILE__)
9
5
 
10
- argument :model_name, type: :string , default: "user"
11
6
  desc """
12
7
  This generator for upgrading sufia-models from 3.7.2 to 4.0 makes the following changes to your application:
13
8
  1. Creates several database migrations if they do not exist in /db/migrate
@@ -16,28 +11,12 @@ This generator for upgrading sufia-models from 3.7.2 to 4.0 makes the following
16
11
  4. Runs full-text generator
17
12
  """
18
13
 
19
- # Implement the required interface for Rails::Generators::Migration.
20
- # taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
21
- def self.next_migration_number(path)
22
- if @prev_migration_nr
23
- @prev_migration_nr += 1
24
- else
25
- if last_migration = Dir[File.join(path, '*.rb')].sort.last
26
- @prev_migration_nr = last_migration.sub(File.join(path, '/'), '').to_i + 1
27
- else
28
- @prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
29
- end
30
- end
31
- @prev_migration_nr.to_s
32
- end
33
-
34
14
  def banner
35
15
  say_status("warning", "UPGRADING SUFIA MODELS", :yellow)
36
16
  end
37
17
 
38
18
  # Setup the database migrations
39
19
  def copy_migrations
40
- # Can't get this any more DRY, because we need this order.
41
20
  [
42
21
  'create_tinymce_assets.rb',
43
22
  'create_content_blocks.rb',
@@ -72,14 +51,4 @@ This generator for upgrading sufia-models from 3.7.2 to 4.0 makes the following
72
51
  def full_text_indexing
73
52
  generate "sufia:models:fulltext"
74
53
  end
75
-
76
- private
77
-
78
- def better_migration_template(file)
79
- begin
80
- migration_template "migrations/#{file}", "db/migrate/#{file}"
81
- rescue Rails::Generators::Error => e
82
- say_status("warning", e.message, :yellow)
83
- end
84
- end
85
54
  end
@@ -0,0 +1,31 @@
1
+ require_relative 'abstract_migration_generator'
2
+
3
+ class Sufia::Models::UserStatsGenerator < Sufia::Models::AbstractMigrationGenerator
4
+ source_root File.expand_path('../templates', __FILE__)
5
+ argument :model_name, type: :string , default: "user"
6
+
7
+ desc """
8
+ This generator adds usage stats methods to the user model in your application:
9
+ """
10
+
11
+ def banner
12
+ say_status("warning", "ADDING USER STATS-RELATED ABILITIES TO SUFIA MODELS", :yellow)
13
+ end
14
+
15
+ # Setup the database migrations
16
+ def copy_migrations
17
+ better_migration_template 'create_user_stats.rb'
18
+ end
19
+
20
+ def add_stats_mixin_to_user_model
21
+ file_path = "app/models/#{model_name.underscore}.rb"
22
+
23
+ if File.exists?(file_path)
24
+ inject_into_file file_path, after: /include Sufia\:\:User.*$/ do
25
+ "\n include Sufia::UserUsageStats"
26
+ end
27
+ else
28
+ puts " \e[31mFailure\e[0m Sufia requires a user object. This generator assumes that the model is defined in the file #{file_path}, which does not exist. If you used a different name, please re-run the generator and provide that name as an argument. Such as \b rails g sufia:models:user_stats client"
29
+ end
30
+ end
31
+ end
@@ -31,10 +31,6 @@ module Sufia
31
31
  # Defaulting analytic start date to when ever the file was uploaded by leaving it blank
32
32
  config.analytic_start_date = nil
33
33
 
34
- config.translate_uri_to_id = lambda { |uri| uri.to_s.split('/')[-1] }
35
- config.translate_id_to_uri = lambda { |id|
36
- "#{ActiveFedora.fedora.host}#{ActiveFedora.fedora.base_path}/#{Sufia::Noid.treeify(id)}" }
37
-
38
34
  config.autoload_paths += %W(
39
35
  #{config.root}/app/models/datastreams
40
36
  )
@@ -62,15 +58,10 @@ module Sufia
62
58
  end
63
59
 
64
60
  initializer 'configure' do
65
- Sufia.config.tap do |c|
66
- Hydra::Derivatives.ffmpeg_path = c.ffmpeg_path
67
- Hydra::Derivatives.temp_file_base = c.temp_file_base
68
- Hydra::Derivatives.fits_path = c.fits_path
69
- Hydra::Derivatives.enable_ffmpeg = c.enable_ffmpeg
70
-
71
- ActiveFedora::Base.translate_uri_to_id = c.translate_uri_to_id
72
- ActiveFedora::Base.translate_id_to_uri = c.translate_id_to_uri
73
- end
61
+ Hydra::Derivatives.ffmpeg_path = Sufia.config.ffmpeg_path
62
+ Hydra::Derivatives.temp_file_base = Sufia.config.temp_file_base
63
+ Hydra::Derivatives.fits_path = Sufia.config.fits_path
64
+ Hydra::Derivatives.enable_ffmpeg = Sufia.config.enable_ffmpeg
74
65
  end
75
66
  end
76
67
  end
@@ -1,27 +1,23 @@
1
1
  module Sufia
2
2
  module FileContent
3
3
  module Versions
4
- extend ActiveSupport::Concern
5
-
6
- included do
7
- has_many_versions
4
+ def get_version(version_id)
5
+ self.versions.select { |v| v.versionID == version_id}.first
8
6
  end
9
7
 
10
8
  def latest_version
11
- versions.last.label unless versions.empty?
9
+ self.versions.first
12
10
  end
13
11
 
14
12
  def version_committer(version)
15
- vc = VersionCommitter.where(version_id: version)
13
+ vc = VersionCommitter.where(obj_id: version.pid,
14
+ datastream_id: version.dsid,
15
+ version_id: version.versionID)
16
16
  return vc.empty? ? nil : vc.first.committer_login
17
17
  end
18
18
 
19
- def save
20
- super.tap do |passing|
21
- create_version if passing
22
- end
23
- end
24
-
19
+
25
20
  end
26
21
  end
27
22
  end
23
+
@@ -0,0 +1,89 @@
1
+ module Sufia
2
+ class UserStatImporter
3
+
4
+ def initialize(options={})
5
+ @verbose = options[:verbose]
6
+ @logging = options[:logging]
7
+ end
8
+
9
+ def import
10
+ log_message('Begin import of User stats.')
11
+ ::User.find_each do |user|
12
+ start_date = date_since_last_cache(user)
13
+
14
+ stats = {}
15
+ file_ids_for_user(user).each do |file_id|
16
+ view_stats = FileViewStat.statistics(file_id, start_date, user.id)
17
+ stats = tally_results(view_stats, :views, stats)
18
+
19
+ dl_stats = FileDownloadStat.statistics(file_id, start_date, user.id)
20
+ stats = tally_results(dl_stats, :downloads, stats)
21
+ end
22
+
23
+ create_or_update_user_stats(stats, user)
24
+ end
25
+ log_message('User stats import complete.')
26
+ end
27
+
28
+
29
+ private
30
+
31
+ def date_since_last_cache(user)
32
+ last_cached_stat = UserStat.where(user_id: user.id).order(date: :asc).last
33
+
34
+ if last_cached_stat
35
+ last_cached_stat.date + 1.day
36
+ else
37
+ Sufia.config.analytic_start_date
38
+ end
39
+ end
40
+
41
+ def file_ids_for_user(user)
42
+ ids = []
43
+ ::GenericFile.find_in_batches("#{Solrizer.solr_name('depositor', :symbol)}:\"#{user.user_key}\"", fl:"id") do |group|
44
+ ids.concat group.map { |doc| doc["id"] }
45
+ end
46
+ ids
47
+ end
48
+
49
+ # For each date, add the view and download counts for this
50
+ # file to the view & download sub-totals for that day.
51
+ # The resulting hash will look something like this:
52
+ # {"2014-11-30 00:00:00 UTC" => {:views=>2, :downloads=>5},
53
+ # "2014-12-01 00:00:00 UTC" => {:views=>4, :downloads=>4}}
54
+ def tally_results(file_stats, stat_name, total_stats)
55
+ file_stats.each do |stats|
56
+ # Exclude the stats from today since it will only be a partial day's worth of data
57
+ break if stats.date == Date.today
58
+
59
+ date_key = stats.date.to_s
60
+ old_count = total_stats[date_key] ? total_stats[date_key].fetch(stat_name) { 0 } : 0
61
+ new_count = old_count + stats.method(stat_name).call
62
+
63
+ old_values = total_stats[date_key] || {}
64
+ total_stats.store(date_key, old_values)
65
+ total_stats[date_key].store(stat_name, new_count)
66
+ end
67
+ total_stats
68
+ end
69
+
70
+ def create_or_update_user_stats(stats, user)
71
+ stats.each do |date_string, data|
72
+ date = Time.zone.parse(date_string)
73
+
74
+ user_stat = UserStat.where(user_id: user.id).where(date: date).first
75
+ user_stat ||= UserStat.new(user_id: user.id, date: date)
76
+
77
+ user_stat.file_views = data[:views] || 0
78
+ user_stat.file_downloads = data[:downloads] || 0
79
+ user_stat.save!
80
+ end
81
+ end
82
+
83
+ def log_message(message)
84
+ puts message if @verbose
85
+ Rails.logger.info "#{self.class}: #{message}" if @logging
86
+ end
87
+
88
+ end
89
+ end
@@ -1,5 +1,5 @@
1
1
  module Sufia
2
2
  module Models
3
- VERSION = "5.0.0.beta1"
3
+ VERSION = "5.0.0.rc1"
4
4
  end
5
5
  end
@@ -8,50 +8,32 @@ module Sufia
8
8
  include Hydra::AccessControls::Visibility
9
9
 
10
10
  included do
11
+ has_metadata "rightsMetadata", type: ParanoidRightsDatastream
11
12
  validate :paranoid_permissions
12
13
  end
13
14
 
14
15
  def paranoid_permissions
15
- valid = true
16
- VALIDATIONS.each do |validation|
17
- if validation[:condition].call(self)
18
- errors[validation[:key]] ||= []
19
- errors[validation[:key]] << validation[:message]
20
- valid = false
21
- end
22
- end
23
- return valid
24
- end
25
-
26
- VALIDATIONS = [
27
- {key: :edit_users, message: 'Depositor must have edit access', condition: lambda { |obj| !obj.edit_users.include?(obj.depositor) }},
28
- {key: :edit_groups, message: 'Public cannot have edit access', condition: lambda { |obj| obj.edit_groups.include?('public') }},
29
- {key: :edit_groups, message: 'Registered cannot have edit access', condition: lambda { |obj| obj.edit_groups.include?('registered') }}
30
- ]
31
-
32
-
33
- def clear_permissions!
34
- self.permissions = []
16
+ # let the rightsMetadata ds make this determination
17
+ # - the object instance is passed in for easier access to the props ds
18
+ rightsMetadata.validate(self)
35
19
  end
36
20
 
37
21
  ## Updates those permissions that are provided to it. Does not replace any permissions unless they are provided
38
- # def permissions=(params)
39
- # raise "Fixme #{params}"
40
- # perm_hash = permission_hash
41
- # params[:new_user_name].each { |name, access| perm_hash['person'][name] = access } if params[:new_user_name].present?
42
- # params[:new_group_name].each { |name, access| perm_hash['group'][name] = access } if params[:new_group_name].present?
22
+ def permissions=(params)
23
+ perm_hash = permission_hash
24
+ params[:new_user_name].each { |name, access| perm_hash['person'][name] = access } if params[:new_user_name].present?
25
+ params[:new_group_name].each { |name, access| perm_hash['group'][name] = access } if params[:new_group_name].present?
43
26
 
44
- # params[:user].each { |name, access| perm_hash['person'][name] = access} if params[:user]
45
- # params[:group].each { |name, access| perm_hash['group'][name] = access if ['read', 'edit'].include?(access)} if params[:group]
27
+ params[:user].each { |name, access| perm_hash['person'][name] = access} if params[:user]
28
+ params[:group].each { |name, access| perm_hash['group'][name] = access if ['read', 'edit'].include?(access)} if params[:group]
46
29
 
47
- # # rightsMetadata.update_permissions(perm_hash)
48
- # end
30
+ rightsMetadata.update_permissions(perm_hash)
31
+ end
49
32
 
50
- # def permissions
51
- # raise "Fixme "
52
- # perms = super
53
- # perms.map {|p| { name: p.name, access: p.access, type:p.type } }
54
- # end
33
+ def permissions
34
+ perms = super
35
+ perms.map {|p| { name: p.name, access: p.access, type:p.type } }
36
+ end
55
37
 
56
38
  private
57
39