sufia-models 5.0.0.beta1 → 5.0.0.rc1

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