sufia-models 4.3.1 → 5.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/actors/sufia/generic_file/actor.rb +7 -10
- data/app/jobs/active_fedora_pid_based_job.rb +2 -3
- data/app/jobs/audit_job.rb +28 -31
- data/app/jobs/batch_update_job.rb +9 -8
- data/app/jobs/import_url_job.rb +2 -2
- data/app/models/batch.rb +11 -12
- data/app/models/checksum_audit_log.rb +7 -8
- data/app/models/concerns/sufia/ability.rb +4 -6
- data/app/models/concerns/sufia/collection.rb +4 -5
- data/app/models/concerns/sufia/file_stat_utils.rb +3 -3
- data/app/models/concerns/sufia/generic_file.rb +16 -14
- data/app/models/concerns/sufia/generic_file/audit.rb +50 -31
- data/app/models/concerns/sufia/generic_file/characterization.rb +3 -3
- data/app/models/concerns/sufia/generic_file/derivatives.rb +5 -5
- data/app/models/concerns/sufia/generic_file/full_text_indexing.rb +2 -2
- data/app/models/concerns/sufia/generic_file/metadata.rb +82 -11
- data/app/models/concerns/sufia/generic_file/proxy_deposit.rb +12 -3
- data/app/models/concerns/sufia/generic_file/versions.rb +1 -4
- data/app/models/concerns/sufia/generic_file/web_form.rb +13 -6
- data/app/models/concerns/sufia/model_methods.rb +11 -9
- data/app/models/concerns/sufia/user.rb +11 -28
- data/app/models/datastreams/file_content_datastream.rb +1 -1
- data/app/models/datastreams/fits_datastream.rb +1 -1
- data/app/models/file_download_stat.rb +2 -2
- data/app/models/file_usage.rb +5 -9
- data/app/models/file_view_stat.rb +2 -2
- data/app/models/local_authority.rb +2 -2
- data/app/models/proxy_deposit_request.rb +1 -1
- data/app/services/sufia/id_service.rb +5 -5
- data/app/services/sufia/noid.rb +10 -7
- data/lib/generators/sufia/models/cached_stats_generator.rb +31 -2
- data/lib/generators/sufia/models/install_generator.rb +31 -11
- data/lib/generators/sufia/models/proxies_generator.rb +31 -2
- data/lib/generators/sufia/models/templates/config/sufia.rb +10 -3
- data/lib/generators/sufia/models/upgrade400_generator.rb +33 -2
- data/lib/sufia/models/engine.rb +13 -4
- data/lib/sufia/models/file_content/versions.rb +12 -8
- data/lib/sufia/models/version.rb +1 -1
- data/lib/sufia/permissions/writable.rb +34 -16
- data/sufia-models.gemspec +4 -2
- metadata +91 -79
- data/app/models/concerns/sufia/generic_file/reload_on_save.rb +0 -18
- data/app/models/concerns/sufia/properties_datastream_behavior.rb +0 -32
- data/app/models/concerns/sufia/user_usage_stats.rb +0 -15
- data/app/models/datastreams/batch_rdf_datastream.rb +0 -6
- data/app/models/datastreams/generic_file_rdf_datastream.rb +0 -69
- data/app/models/datastreams/paranoid_rights_datastream.rb +0 -22
- data/app/models/datastreams/properties_datastream.rb +0 -4
- data/app/models/sufia/orcid_validator.rb +0 -8
- data/app/models/user_stat.rb +0 -2
- data/lib/generators/sufia/models/abstract_migration_generator.rb +0 -30
- data/lib/generators/sufia/models/orcid_field_generator.rb +0 -19
- data/lib/generators/sufia/models/templates/migrations/add_orcid_to_users.rb +0 -5
- data/lib/generators/sufia/models/templates/migrations/create_user_stats.rb +0 -19
- data/lib/generators/sufia/models/user_stats_generator.rb +0 -31
- data/lib/sufia/models/stats/user_stat_importer.rb +0 -85
- data/lib/tasks/stats_tasks.rake +0 -12
@@ -1,18 +0,0 @@
|
|
1
|
-
# add this in here until we can use a version of Active Fedora that contains this ability
|
2
|
-
module Sufia
|
3
|
-
module GenericFile
|
4
|
-
module ReloadOnSave
|
5
|
-
|
6
|
-
attr_writer :reload_on_save
|
7
|
-
|
8
|
-
def reload_on_save?
|
9
|
-
!!@reload_on_save
|
10
|
-
end
|
11
|
-
|
12
|
-
def refresh
|
13
|
-
self.reload if reload_on_save?
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
@@ -1,32 +0,0 @@
|
|
1
|
-
module Sufia
|
2
|
-
module PropertiesDatastreamBehavior
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
included do
|
6
|
-
set_terminology do |t|
|
7
|
-
t.root(path: "fields")
|
8
|
-
# This is where we put the user id of the object depositor -- impacts permissions/access controls
|
9
|
-
t.depositor index_as: [:symbol, :stored_searchable]
|
10
|
-
# This is where we put the relative path of the file if submitted as a folder
|
11
|
-
t.relative_path
|
12
|
-
t.import_url path: 'importUrl', index_as: :symbol
|
13
|
-
t.proxy_depositor path: 'proxyDepositor', index_as: :symbol
|
14
|
-
# This value is set when a user indicates they are depositing this for someone else
|
15
|
-
t.on_behalf_of path: 'onBehalfOf', index_as: :symbol
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
module ClassMethods
|
20
|
-
def xml_template
|
21
|
-
builder = Nokogiri::XML::Builder.new do |xml|
|
22
|
-
xml.fields
|
23
|
-
end
|
24
|
-
builder.doc
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def prefix
|
29
|
-
""
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
module Sufia::UserUsageStats
|
2
|
-
|
3
|
-
def stats
|
4
|
-
@stats ||= UserStat.where(user_id: id).order(date: :asc)
|
5
|
-
end
|
6
|
-
|
7
|
-
def total_file_views
|
8
|
-
stats.reduce(0) { |total, stat| total + stat.file_views }
|
9
|
-
end
|
10
|
-
|
11
|
-
def total_file_downloads
|
12
|
-
stats.reduce(0) { |total, stat| total + stat.file_downloads }
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|
@@ -1,69 +0,0 @@
|
|
1
|
-
class GenericFileRdfDatastream < ActiveFedora::NtriplesRDFDatastream
|
2
|
-
property :part_of, predicate: RDF::DC.isPartOf
|
3
|
-
property :resource_type, predicate: RDF::DC.type do |index|
|
4
|
-
index.as :stored_searchable, :facetable
|
5
|
-
end
|
6
|
-
property :title, predicate: RDF::DC.title do |index|
|
7
|
-
index.as :stored_searchable, :facetable
|
8
|
-
end
|
9
|
-
property :creator, predicate: RDF::DC.creator do |index|
|
10
|
-
index.as :stored_searchable, :facetable
|
11
|
-
end
|
12
|
-
property :contributor, predicate: RDF::DC.contributor do |index|
|
13
|
-
index.as :stored_searchable, :facetable
|
14
|
-
end
|
15
|
-
property :description, predicate: RDF::DC.description do |index|
|
16
|
-
index.type :text
|
17
|
-
index.as :stored_searchable
|
18
|
-
end
|
19
|
-
property :tag, predicate: RDF::DC.relation do |index|
|
20
|
-
index.as :stored_searchable, :facetable
|
21
|
-
end
|
22
|
-
property :rights, predicate: RDF::DC.rights do |index|
|
23
|
-
index.as :stored_searchable
|
24
|
-
end
|
25
|
-
property :publisher, predicate: RDF::DC.publisher do |index|
|
26
|
-
index.as :stored_searchable, :facetable
|
27
|
-
end
|
28
|
-
property :date_created, predicate: RDF::DC.created do |index|
|
29
|
-
index.as :stored_searchable
|
30
|
-
end
|
31
|
-
property :date_uploaded, predicate: RDF::DC.dateSubmitted do |index|
|
32
|
-
index.type :date
|
33
|
-
index.as :stored_sortable
|
34
|
-
end
|
35
|
-
property :date_modified, predicate: RDF::DC.modified do |index|
|
36
|
-
index.type :date
|
37
|
-
index.as :stored_sortable
|
38
|
-
end
|
39
|
-
property :subject, predicate: RDF::DC.subject do |index|
|
40
|
-
index.as :stored_searchable, :facetable
|
41
|
-
end
|
42
|
-
property :language, predicate: RDF::DC.language do |index|
|
43
|
-
index.as :stored_searchable, :facetable
|
44
|
-
end
|
45
|
-
property :identifier, predicate: RDF::DC.identifier do |index|
|
46
|
-
index.as :stored_searchable
|
47
|
-
end
|
48
|
-
property :based_near, predicate: RDF::FOAF.based_near do |index|
|
49
|
-
index.as :stored_searchable, :facetable
|
50
|
-
end
|
51
|
-
property :related_url, predicate: RDF::RDFS.seeAlso do |index|
|
52
|
-
index.as :stored_searchable
|
53
|
-
end
|
54
|
-
property :bibliographic_citation, predicate: RDF::DC.bibliographicCitation do |index|
|
55
|
-
index.as :stored_searchable
|
56
|
-
end
|
57
|
-
property :source, predicate: RDF::DC.source do |index|
|
58
|
-
index.as :stored_searchable
|
59
|
-
end
|
60
|
-
|
61
|
-
# TODO: Move this somewhere more appropriate
|
62
|
-
begin
|
63
|
-
LocalAuthority.register_vocabulary(self, "subject", "lc_subjects")
|
64
|
-
LocalAuthority.register_vocabulary(self, "language", "lexvo_languages")
|
65
|
-
LocalAuthority.register_vocabulary(self, "tag", "lc_genres")
|
66
|
-
rescue
|
67
|
-
puts "tables for vocabularies missing"
|
68
|
-
end
|
69
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
# subclass built-in Hydra RightsDatastream and build in extra model-level validation
|
2
|
-
class ParanoidRightsDatastream < Hydra::Datastream::RightsMetadata
|
3
|
-
use_terminology Hydra::Datastream::RightsMetadata
|
4
|
-
|
5
|
-
VALIDATIONS = [
|
6
|
-
{key: :edit_users, message: 'Depositor must have edit access', condition: lambda { |obj| !obj.edit_users.include?(obj.depositor) }},
|
7
|
-
{key: :edit_groups, message: 'Public cannot have edit access', condition: lambda { |obj| obj.edit_groups.include?('public') }},
|
8
|
-
{key: :edit_groups, message: 'Registered cannot have edit access', condition: lambda { |obj| obj.edit_groups.include?('registered') }}
|
9
|
-
]
|
10
|
-
|
11
|
-
def validate(object)
|
12
|
-
valid = true
|
13
|
-
VALIDATIONS.each do |validation|
|
14
|
-
if validation[:condition].call(object)
|
15
|
-
object.errors[validation[:key]] ||= []
|
16
|
-
object.errors[validation[:key]] << validation[:message]
|
17
|
-
valid = false
|
18
|
-
end
|
19
|
-
end
|
20
|
-
return valid
|
21
|
-
end
|
22
|
-
end
|
@@ -1,8 +0,0 @@
|
|
1
|
-
module Sufia
|
2
|
-
class OrcidValidator < ActiveModel::Validator
|
3
|
-
def validate(record)
|
4
|
-
return if record.orcid.blank?
|
5
|
-
record.errors.add(:orcid, 'must be a string of 19 characters, e.g., "0000-0000-0000-0000"') unless /\d{4}-\d{4}-\d{4}-\d{4}/.match(record.orcid)
|
6
|
-
end
|
7
|
-
end
|
8
|
-
end
|
data/app/models/user_stat.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
# -*- encoding : utf-8 -*-
|
2
|
-
require 'rails/generators'
|
3
|
-
require 'rails/generators/migration'
|
4
|
-
|
5
|
-
class Sufia::Models::AbstractMigrationGenerator < Rails::Generators::Base
|
6
|
-
include Rails::Generators::Migration
|
7
|
-
|
8
|
-
# Implement the required interface for Rails::Generators::Migration.
|
9
|
-
# taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
|
10
|
-
def self.next_migration_number(path)
|
11
|
-
if @prev_migration_nr
|
12
|
-
@prev_migration_nr += 1
|
13
|
-
else
|
14
|
-
if last_migration = Dir[File.join(path, '*.rb')].sort.last
|
15
|
-
@prev_migration_nr = last_migration.sub(File.join(path, '/'), '').to_i + 1
|
16
|
-
else
|
17
|
-
@prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
18
|
-
end
|
19
|
-
end
|
20
|
-
@prev_migration_nr.to_s
|
21
|
-
end
|
22
|
-
|
23
|
-
protected
|
24
|
-
|
25
|
-
def better_migration_template(file)
|
26
|
-
migration_template "migrations/#{file}", "db/migrate/#{file}"
|
27
|
-
rescue Rails::Generators::Error => e
|
28
|
-
say_status("warning", e.message, :yellow)
|
29
|
-
end
|
30
|
-
end
|
@@ -1,19 +0,0 @@
|
|
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,19 +0,0 @@
|
|
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,31 +0,0 @@
|
|
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
|
@@ -1,85 +0,0 @@
|
|
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
|
-
files_for_user(user).each do |file|
|
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 files_for_user(user)
|
42
|
-
::GenericFile.where(Solrizer.solr_name('depositor', :symbol) => user.user_key)
|
43
|
-
end
|
44
|
-
|
45
|
-
# For each date, add the view and download counts for this
|
46
|
-
# file to the view & download sub-totals for that day.
|
47
|
-
# The resulting hash will look something like this:
|
48
|
-
# {"2014-11-30 00:00:00 UTC" => {:views=>2, :downloads=>5},
|
49
|
-
# "2014-12-01 00:00:00 UTC" => {:views=>4, :downloads=>4}}
|
50
|
-
def tally_results(file_stats, stat_name, total_stats)
|
51
|
-
file_stats.each do |stats|
|
52
|
-
# Exclude the stats from today since it will only be a partial day's worth of data
|
53
|
-
break if stats.date == Date.today
|
54
|
-
|
55
|
-
date_key = stats.date.to_s
|
56
|
-
old_count = total_stats[date_key] ? total_stats[date_key].fetch(stat_name) { 0 } : 0
|
57
|
-
new_count = old_count + stats.method(stat_name).call
|
58
|
-
|
59
|
-
old_values = total_stats[date_key] || {}
|
60
|
-
total_stats.store(date_key, old_values)
|
61
|
-
total_stats[date_key].store(stat_name, new_count)
|
62
|
-
end
|
63
|
-
total_stats
|
64
|
-
end
|
65
|
-
|
66
|
-
def create_or_update_user_stats(stats, user)
|
67
|
-
stats.each do |date_string, data|
|
68
|
-
date = Time.zone.parse(date_string)
|
69
|
-
|
70
|
-
user_stat = UserStat.where(user_id: user.id).where(date: date).first
|
71
|
-
user_stat ||= UserStat.new(user_id: user.id, date: date)
|
72
|
-
|
73
|
-
user_stat.file_views = data[:views] || 0
|
74
|
-
user_stat.file_downloads = data[:downloads] || 0
|
75
|
-
user_stat.save!
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def log_message(message)
|
80
|
-
puts message if @verbose
|
81
|
-
Rails.logger.info "#{self.class}: #{message}" if @logging
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
85
|
-
end
|
data/lib/tasks/stats_tasks.rake
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
namespace :sufia do
|
2
|
-
namespace :stats do
|
3
|
-
|
4
|
-
desc "Cache file view & download stats for all users"
|
5
|
-
task :user_stats => :environment do
|
6
|
-
require 'sufia/models/stats/user_stat_importer'
|
7
|
-
importer = Sufia::UserStatImporter.new(verbose: true, logging: true)
|
8
|
-
importer.import
|
9
|
-
end
|
10
|
-
|
11
|
-
end
|
12
|
-
end
|