curation_concerns-models 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.md +177 -0
- data/README.md +42 -0
- data/Rakefile +1 -0
- data/app/actors/concerns/curation_concerns/manages_embargoes_actor.rb +99 -0
- data/app/actors/curation_concerns/base_actor.rb +90 -0
- data/app/actors/curation_concerns/generic_file_actor.rb +150 -0
- data/app/actors/curation_concerns/work_actor_behavior.rb +88 -0
- data/app/jobs/active_fedora_id_based_job.rb +22 -0
- data/app/jobs/active_fedora_pid_based_job.rb +6 -0
- data/app/jobs/audit_job.rb +58 -0
- data/app/jobs/characterize_job.rb +11 -0
- data/app/jobs/copy_permissions_job.rb +24 -0
- data/app/jobs/create_derivatives_job.rb +15 -0
- data/app/jobs/import_url_job.rb +56 -0
- data/app/jobs/ingest_local_file_job.rb +48 -0
- data/app/jobs/resolrize_job.rb +9 -0
- data/app/models/checksum_audit_log.rb +21 -0
- data/app/models/concerns/curation_concerns/ability.rb +34 -0
- data/app/models/concerns/curation_concerns/basic_metadata.rb +87 -0
- data/app/models/concerns/curation_concerns/collection_behavior.rb +47 -0
- data/app/models/concerns/curation_concerns/generic_file/belongs_to_works.rb +53 -0
- data/app/models/concerns/curation_concerns/generic_file/characterization.rb +89 -0
- data/app/models/concerns/curation_concerns/generic_file/content.rb +8 -0
- data/app/models/concerns/curation_concerns/generic_file/export.rb +343 -0
- data/app/models/concerns/curation_concerns/generic_file/full_text_indexing.rb +12 -0
- data/app/models/concerns/curation_concerns/generic_file/indexing.rb +14 -0
- data/app/models/concerns/curation_concerns/generic_file/versions.rb +16 -0
- data/app/models/concerns/curation_concerns/generic_file.rb +5 -0
- data/app/models/concerns/curation_concerns/generic_file_behavior.rb +44 -0
- data/app/models/concerns/curation_concerns/generic_work_behavior.rb +38 -0
- data/app/models/concerns/curation_concerns/has_representative.rb +14 -0
- data/app/models/concerns/curation_concerns/human_readable_type.rb +23 -0
- data/app/models/concerns/curation_concerns/permissions/readable.rb +19 -0
- data/app/models/concerns/curation_concerns/permissions/writable.rb +75 -0
- data/app/models/concerns/curation_concerns/permissions.rb +7 -0
- data/app/models/concerns/curation_concerns/serializers.rb +15 -0
- data/app/models/concerns/curation_concerns/solr_document_behavior.rb +135 -0
- data/app/models/concerns/curation_concerns/user.rb +65 -0
- data/app/models/concerns/curation_concerns/with_basic_metadata.rb +98 -0
- data/app/models/concerns/curation_concerns/with_generic_files.rb +29 -0
- data/app/models/curation_concerns/classify_concern.rb +47 -0
- data/app/models/curation_concerns/quick_classification_query.rb +31 -0
- data/app/models/datastreams/fits_datastream.rb +148 -0
- data/app/models/version_committer.rb +2 -0
- data/app/services/curation_concerns/characterization_service.rb +71 -0
- data/app/services/curation_concerns/full_text_extraction_service.rb +38 -0
- data/app/services/curation_concerns/generic_file_audit_service.rb +85 -0
- data/app/services/curation_concerns/generic_file_indexing_service.rb +14 -0
- data/app/services/curation_concerns/generic_work_indexing_service.rb +16 -0
- data/app/services/curation_concerns/noid.rb +23 -0
- data/app/services/curation_concerns/repository_audit_service.rb +9 -0
- data/app/services/curation_concerns/versioning_service.rb +27 -0
- data/config/locales/curation_concerns.en.yml +6 -0
- data/curation_concerns-models.gemspec +34 -0
- data/lib/curation_concerns/messages.rb +66 -0
- data/lib/curation_concerns/models/engine.rb +61 -0
- data/lib/curation_concerns/models/resque.rb +36 -0
- data/lib/curation_concerns/models/utils.rb +22 -0
- data/lib/curation_concerns/models/version.rb +5 -0
- data/lib/curation_concerns/models.rb +32 -0
- data/lib/generators/curation_concerns/models/abstract_migration_generator.rb +30 -0
- data/lib/generators/curation_concerns/models/clamav_generator.rb +19 -0
- data/lib/generators/curation_concerns/models/fulltext_generator.rb +28 -0
- data/lib/generators/curation_concerns/models/install_generator.rb +70 -0
- data/lib/generators/curation_concerns/models/templates/app/models/collection.rb +4 -0
- data/lib/generators/curation_concerns/models/templates/app/models/generic_file.rb +4 -0
- data/lib/generators/curation_concerns/models/templates/config/clamav.rb +1 -0
- data/lib/generators/curation_concerns/models/templates/config/curation_concerns.rb +123 -0
- data/lib/generators/curation_concerns/models/templates/config/mime_types.rb +6 -0
- data/lib/generators/curation_concerns/models/templates/config/redis.yml +9 -0
- data/lib/generators/curation_concerns/models/templates/config/redis_config.rb +32 -0
- data/lib/generators/curation_concerns/models/templates/config/resque-pool.yml +1 -0
- data/lib/generators/curation_concerns/models/templates/config/resque_admin.rb +10 -0
- data/lib/generators/curation_concerns/models/templates/config/resque_config.rb +5 -0
- data/lib/generators/curation_concerns/models/templates/migrations/create_checksum_audit_logs.rb +19 -0
- data/lib/generators/curation_concerns/models/templates/migrations/create_version_committers.rb +15 -0
- data/lib/tasks/curation_concerns-models_tasks.rake +75 -0
- data/lib/tasks/migrate.rake +13 -0
- data/lib/tasks/resque.rake +13 -0
- data/lib/tasks/solr_reindex.rake +8 -0
- metadata +282 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
class GenericFileAuditService
|
|
3
|
+
attr_reader :generic_file
|
|
4
|
+
def initialize(file)
|
|
5
|
+
@generic_file = file
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
NO_RUNS = 999
|
|
9
|
+
|
|
10
|
+
# provides a human readable version of the audit status
|
|
11
|
+
def human_readable_audit_status(stat)
|
|
12
|
+
case stat
|
|
13
|
+
when 0
|
|
14
|
+
'failing'
|
|
15
|
+
when 1
|
|
16
|
+
'passing'
|
|
17
|
+
else
|
|
18
|
+
stat
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Audits each version of each file if it hasn't been audited recently
|
|
23
|
+
# Returns the set of most recent audit status for each version of the content file
|
|
24
|
+
# @param [Hash] log container for messages, mapping file ids to status
|
|
25
|
+
def audit(log={})
|
|
26
|
+
generic_file.files.each { |f| log[f.id] = audit_file(f) }
|
|
27
|
+
log
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# Retrieve or generate the audit check for a file (all versions are checked for versioned files)
|
|
33
|
+
# @param [ActiveFedora::File] file to audit
|
|
34
|
+
# @param [Array] log container for messages
|
|
35
|
+
def audit_file(file, log=[])
|
|
36
|
+
versions = file.has_versions? ? file.versions.all : file
|
|
37
|
+
versions.each { |v| log << audit_file_version(file.id, v.uri) }
|
|
38
|
+
log
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Retrieve or generate the audit check for a file and provide a human-readable status message.
|
|
42
|
+
# @param [ActiveFedora::File] file to audit
|
|
43
|
+
def audit_stat(file)
|
|
44
|
+
audit_results = audit_file(file).collect { |result| result["pass"] }
|
|
45
|
+
# check how many non runs we had
|
|
46
|
+
non_runs = audit_results.reduce(0) { |sum, value| value == NO_RUNS ? sum += 1 : sum }
|
|
47
|
+
if non_runs == 0
|
|
48
|
+
audit_results.reduce(true) { |sum, value| sum && value }
|
|
49
|
+
elsif non_runs < audit_results.length
|
|
50
|
+
result = audit_results.reduce(true) { |sum, value| value == NO_RUNS ? sum : sum && value }
|
|
51
|
+
"Some audits have not been run, but the ones run were #{human_readable_audit_status(result)}."
|
|
52
|
+
else
|
|
53
|
+
'Audits have not yet been run on this file.'
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Retrieve or generate the audit check for a specific version of a file
|
|
58
|
+
# @param [String] file_id used to find the file within its parent object (usually "original_file")
|
|
59
|
+
# @param [String] version_uri the version to be audited (or the file uri for non-versioned files)
|
|
60
|
+
def audit_file_version(file_id, version_uri)
|
|
61
|
+
latest_audit = ChecksumAuditLog.logs_for(generic_file.id, file_id).first
|
|
62
|
+
return latest_audit unless needs_audit?(latest_audit)
|
|
63
|
+
CurationConcerns.queue.push(AuditJob.new(generic_file.id, file_id, version_uri))
|
|
64
|
+
latest_audit || ChecksumAuditLog.new(pass: NO_RUNS, generic_file_id: generic_file.id, file_id: file_id, version: version_uri)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Check if time since the last audit is greater than the maximum days allowed between audits
|
|
68
|
+
# @param [ChecksumAuditLog] latest_audit the most recent audit event
|
|
69
|
+
def needs_audit?(latest_audit)
|
|
70
|
+
return true unless latest_audit
|
|
71
|
+
unless latest_audit.updated_at
|
|
72
|
+
logger.warn "***AUDIT*** problem with audit log! Latest Audit is not nil, but updated_at is not set #{latest_audit}"
|
|
73
|
+
return true
|
|
74
|
+
end
|
|
75
|
+
days_since_last_audit(latest_audit) >= CurationConcerns.config.max_days_between_audits
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Return the number of days since the latest audit event
|
|
79
|
+
# @param [ChecksumAuditLog] latest_audit the most recent audit event
|
|
80
|
+
def days_since_last_audit(latest_audit)
|
|
81
|
+
(DateTime.now - latest_audit.updated_at.to_date).to_i
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
class GenericFileIndexingService < ActiveFedora::IndexingService
|
|
3
|
+
def generate_solr_document
|
|
4
|
+
super.tap do |solr_doc|
|
|
5
|
+
solr_doc[Solrizer.solr_name('label')] = object.label
|
|
6
|
+
solr_doc[Solrizer.solr_name('file_format')] = object.file_format
|
|
7
|
+
solr_doc[Solrizer.solr_name('file_format', :facetable)] = object.file_format
|
|
8
|
+
solr_doc[Solrizer.solr_name(:file_size, :symbol)] = object.file_size[0]
|
|
9
|
+
solr_doc['all_text_timv'] = object.full_text.content
|
|
10
|
+
solr_doc[Solrizer.solr_name('generic_work_ids', :symbol)] = object.generic_work_ids unless object.generic_work_ids.empty?
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
class GenericWorkIndexingService < ActiveFedora::IndexingService
|
|
3
|
+
|
|
4
|
+
def generate_solr_document
|
|
5
|
+
super.tap do |solr_doc|
|
|
6
|
+
# We know that all the members of GenericWorks are GenericFiles so we can use
|
|
7
|
+
# member_ids which requires fewer Fedora API calls than generic_file_ids.
|
|
8
|
+
# generic_file_ids requires loading all the members from Fedora but member_ids
|
|
9
|
+
# looks just at solr
|
|
10
|
+
solr_doc[Solrizer.solr_name('generic_file_ids', :symbol)] = object.member_ids
|
|
11
|
+
Solrizer.set_field(solr_doc, 'generic_type', 'Work', :facetable)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'active_fedora/noid'
|
|
2
|
+
|
|
3
|
+
module CurationConcerns
|
|
4
|
+
module Noid
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
## This overrides the default behavior, which is to ask Fedora for an id
|
|
8
|
+
# @see ActiveFedora::Persistence.assign_id
|
|
9
|
+
def assign_id
|
|
10
|
+
service.mint if CurationConcerns.config.enable_noids
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_param
|
|
14
|
+
id
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def service
|
|
20
|
+
@service ||= ActiveFedora::Noid::Service.new
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
class VersioningService
|
|
3
|
+
# Make a version and record the version committer
|
|
4
|
+
# @param [ActiveFedora::File] content
|
|
5
|
+
# @param [User] user
|
|
6
|
+
def self.create(content, user=nil)
|
|
7
|
+
content.create_version
|
|
8
|
+
record_committer(content, user) if user
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @param [ActiveFedora::File] file
|
|
12
|
+
def self.latest_version_of(file)
|
|
13
|
+
file.versions.last
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
protected
|
|
17
|
+
|
|
18
|
+
# Record the version committer of the last version
|
|
19
|
+
# @param [ActiveFedora::File] content
|
|
20
|
+
# @param [User] user
|
|
21
|
+
def self.record_committer(content, user)
|
|
22
|
+
version = latest_version_of(content)
|
|
23
|
+
return if version.nil?
|
|
24
|
+
VersionCommitter.create(version_id: version.uri, committer_login: user.user_key)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
version = File.read(File.expand_path("../../VERSION", __FILE__)).strip
|
|
3
|
+
|
|
4
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
6
|
+
|
|
7
|
+
Gem::Specification.new do |spec|
|
|
8
|
+
spec.name = "curation_concerns-models"
|
|
9
|
+
spec.version = version
|
|
10
|
+
spec.authors = ["Justin Coyne"]
|
|
11
|
+
spec.email = ["justin@curationexperts.com"]
|
|
12
|
+
spec.summary = %q{Simple institutional repository models for Hydra}
|
|
13
|
+
spec.description = %q{An extensible repository data-model with works and and many attached files}
|
|
14
|
+
spec.homepage = ""
|
|
15
|
+
spec.license = "APACHE2"
|
|
16
|
+
|
|
17
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
20
|
+
spec.require_paths = ["lib"]
|
|
21
|
+
|
|
22
|
+
spec.add_dependency 'active_attr'
|
|
23
|
+
spec.add_dependency 'nest', '~> 1.1'
|
|
24
|
+
spec.add_dependency 'hydra-collections', '~> 6.0.0.alpha'
|
|
25
|
+
spec.add_dependency 'hydra-head', '~> 9.2.2'
|
|
26
|
+
spec.add_dependency 'hydra-works', '~> 0.1'
|
|
27
|
+
spec.add_dependency 'active-fedora', '~> 9.3.0'
|
|
28
|
+
spec.add_dependency 'active_fedora-noid', '~> 1.0.2'
|
|
29
|
+
spec.add_dependency 'resque', '~> 1.23'
|
|
30
|
+
spec.add_dependency 'resque-pool', '~> 0.3'
|
|
31
|
+
|
|
32
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
|
33
|
+
spec.add_development_dependency 'rake'
|
|
34
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
module Messages
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
# Borrowed from AbstractController so we can render html content tags
|
|
6
|
+
attr_accessor :output_buffer
|
|
7
|
+
include ActionView::Helpers::TagHelper
|
|
8
|
+
include ActionView::Helpers::UrlHelper
|
|
9
|
+
|
|
10
|
+
def success_subject
|
|
11
|
+
I18n.t("curation_concerns.messages.success.subject")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def failure_subject
|
|
15
|
+
I18n.t("curation_concerns.messages.failure.subject")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def single_success id, file
|
|
19
|
+
content_tag :span, id: "ss-"+id do
|
|
20
|
+
[link_to_file(file), I18n.t("curation_concerns.messages.success.single")].join(" ").html_safe
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def multiple_success id, files
|
|
25
|
+
content_tag :span, id: "ss-"+id do
|
|
26
|
+
[success_link(files), I18n.t("curation_concerns.messages.success.multiple.tag")].join(" ").html_safe
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def single_failure id, file
|
|
31
|
+
content_tag :span, id: "ss-"+id do
|
|
32
|
+
[link_to_file(file), I18n.t("curation_concerns.messages.failure.single")].join(" ").html_safe
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def multiple_failure id, files
|
|
37
|
+
content_tag :span, id: "ss-"+id do
|
|
38
|
+
[failure_link(files), I18n.t("curation_concerns.messages.failure.multiple.tag")].join(" ").html_safe
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Double-quotes are replaced with single ones so this list can be included in a data block. Ex:
|
|
43
|
+
# <a href="#" data-content="<a href='#'>embedded link</a>" rel="popover">Click me</a>
|
|
44
|
+
def file_list files
|
|
45
|
+
files.map { |gf| link_to_file(gf) }.join(', ').gsub(/"/, "'")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def link_to_file file
|
|
49
|
+
link_to(file.to_s, Rails.application.class.routes.url_helpers.curation_concerns_generic_file_path(file))
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def success_link files
|
|
55
|
+
link_to I18n.t("curation_concerns.messages.success.multiple.link"), "#",
|
|
56
|
+
rel: "popover",
|
|
57
|
+
data: { content: file_list(files).html_safe, title: I18n.t("curation_concerns.messages.success.title") }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def failure_link files
|
|
61
|
+
link_to I18n.t("curation_concerns.messages.failure.multiple.link"), "#",
|
|
62
|
+
rel: "popover",
|
|
63
|
+
data: { content: file_list(files).html_safe, title: I18n.t("curation_concerns.messages.failure.title") }
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
module Models
|
|
3
|
+
|
|
4
|
+
def self.config(&block)
|
|
5
|
+
@@config ||= Engine::Configuration.new
|
|
6
|
+
yield @@config if block
|
|
7
|
+
return @@config
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Engine < ::Rails::Engine
|
|
12
|
+
|
|
13
|
+
require 'curation_concerns/models/resque'
|
|
14
|
+
|
|
15
|
+
# Set some configuration defaults
|
|
16
|
+
config.persistent_hostpath = "http://localhost/files/"
|
|
17
|
+
config.enable_ffmpeg = false
|
|
18
|
+
config.ffmpeg_path = 'ffmpeg'
|
|
19
|
+
config.fits_message_length = 5
|
|
20
|
+
config.temp_file_base = nil
|
|
21
|
+
config.enable_noids = true
|
|
22
|
+
config.noid_template = '.reeddeeddk'
|
|
23
|
+
config.minter_statefile = '/tmp/minter-state'
|
|
24
|
+
config.redis_namespace = "curation_concerns"
|
|
25
|
+
config.fits_path = "fits.sh"
|
|
26
|
+
config.enable_local_ingest = nil
|
|
27
|
+
config.queue = CurationConcerns::Resque::Queue
|
|
28
|
+
|
|
29
|
+
# Defaulting analytic start date to whenever the file was uploaded by leaving it blank
|
|
30
|
+
config.analytic_start_date = nil
|
|
31
|
+
|
|
32
|
+
config.autoload_paths += %W(
|
|
33
|
+
#{config.root}/app/actors/concerns
|
|
34
|
+
#{config.root}/lib/curation_concerns
|
|
35
|
+
#{config.root}/app/models/datastreams
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
initializer 'requires' do
|
|
39
|
+
require 'active_fedora/noid'
|
|
40
|
+
require 'curation_concerns/noid'
|
|
41
|
+
require 'curation_concerns/permissions'
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
initializer 'configure' do
|
|
45
|
+
CurationConcerns.config.tap do |c|
|
|
46
|
+
Hydra::Derivatives.ffmpeg_path = c.ffmpeg_path
|
|
47
|
+
Hydra::Derivatives.temp_file_base = c.temp_file_base
|
|
48
|
+
Hydra::Derivatives.fits_path = c.fits_path
|
|
49
|
+
Hydra::Derivatives.enable_ffmpeg = c.enable_ffmpeg
|
|
50
|
+
|
|
51
|
+
ActiveFedora::Base.translate_uri_to_id = ActiveFedora::Noid.config.translate_uri_to_id
|
|
52
|
+
ActiveFedora::Base.translate_id_to_uri = ActiveFedora::Noid.config.translate_id_to_uri
|
|
53
|
+
ActiveFedora::Noid.config.template = c.noid_template
|
|
54
|
+
ActiveFedora::Noid.config.statefile = c.minter_statefile
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Borrowed from:
|
|
2
|
+
# https://github.com/jeremy/resque-rails/blob/master/lib/resque/rails/queue.rb
|
|
3
|
+
module CurationConcerns
|
|
4
|
+
module Resque
|
|
5
|
+
class Queue
|
|
6
|
+
attr_reader :default_queue_name
|
|
7
|
+
|
|
8
|
+
def initialize(default_queue_name)
|
|
9
|
+
@default_queue_name = default_queue_name
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def push(job)
|
|
13
|
+
push_tries = 0
|
|
14
|
+
queue = job.respond_to?(:queue_name) ? job.queue_name : default_queue_name
|
|
15
|
+
begin
|
|
16
|
+
::Resque.enqueue_to queue, MarshaledJob, Base64.encode64(Marshal.dump(job))
|
|
17
|
+
rescue Redis::CannotConnectError
|
|
18
|
+
ActiveFedora::Base.logger.error "Redis is down!"
|
|
19
|
+
rescue Redis::TimeoutError => error
|
|
20
|
+
ActiveFedora::Base.logger.warn "Redis Timed out. Trying again! #{job.inspect}"
|
|
21
|
+
push_tries+=1
|
|
22
|
+
# fail for good if the tries is greater than 3
|
|
23
|
+
raise error if push_tries >=3
|
|
24
|
+
sleep 0.01
|
|
25
|
+
retry
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class MarshaledJob
|
|
31
|
+
def self.perform(marshaled_job)
|
|
32
|
+
Marshal.load(Base64.decode64(marshaled_job)).run
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module CurationConcerns
|
|
2
|
+
module Utils
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
def retry_unless(number_of_tries, condition, &block)
|
|
6
|
+
self.class.retry_unless(number_of_tries, condition, &block)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module ClassMethods
|
|
10
|
+
def retry_unless(number_of_tries, condition, &block)
|
|
11
|
+
raise ArgumentError, "First argument must be an enumerator" unless number_of_tries.is_a? Enumerator
|
|
12
|
+
raise ArgumentError, "Second argument must be a lambda" unless condition.respond_to? :call
|
|
13
|
+
raise ArgumentError, "Must pass a block of code to retry" unless block_given?
|
|
14
|
+
number_of_tries.each do
|
|
15
|
+
result = block.call
|
|
16
|
+
return result unless condition.call
|
|
17
|
+
end
|
|
18
|
+
raise RuntimeError, "retry_unless could not complete successfully. Try upping the # of tries?"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require "curation_concerns/models/version"
|
|
2
|
+
require "curation_concerns/models/engine"
|
|
3
|
+
|
|
4
|
+
require 'hydra/head'
|
|
5
|
+
require 'nest'
|
|
6
|
+
# require "active_resource" # used by GenericFile to catch errors & by GeoNamesResource
|
|
7
|
+
require 'resque/server'
|
|
8
|
+
|
|
9
|
+
module CurationConcerns
|
|
10
|
+
extend ActiveSupport::Autoload
|
|
11
|
+
|
|
12
|
+
module Models
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
autoload :Utils, 'curation_concerns/models/utils'
|
|
16
|
+
autoload :Permissions
|
|
17
|
+
autoload :Messages
|
|
18
|
+
|
|
19
|
+
attr_writer :queue
|
|
20
|
+
|
|
21
|
+
def self.queue
|
|
22
|
+
@queue ||= config.queue.new('curation_concerns')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.config(&block)
|
|
26
|
+
@@config ||= CurationConcerns::Models::Engine::Configuration.new
|
|
27
|
+
|
|
28
|
+
yield @@config if block
|
|
29
|
+
|
|
30
|
+
return @@config
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'rails/generators'
|
|
3
|
+
require 'rails/generators/migration'
|
|
4
|
+
|
|
5
|
+
class CurationConcerns::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
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'rails/generators'
|
|
3
|
+
|
|
4
|
+
class CurationConcerns::Models::ClamavGenerator < Rails::Generators::Base
|
|
5
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
6
|
+
|
|
7
|
+
desc """
|
|
8
|
+
This generator makes the following changes to your application:
|
|
9
|
+
1. Generates clamav initializer
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def banner
|
|
13
|
+
say_status("info", "Generating clamav initializers", :blue)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def create_initializer_file
|
|
17
|
+
copy_file 'config/clamav.rb', 'config/initializers/clamav.rb'
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
|
2
|
+
require 'rails/generators'
|
|
3
|
+
|
|
4
|
+
class CurationConcerns::Models::FulltextGenerator < Rails::Generators::Base
|
|
5
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
6
|
+
|
|
7
|
+
desc """
|
|
8
|
+
This generator makes the following changes to your application:
|
|
9
|
+
1. Copies solrconfig.xml into solr_conf/conf/
|
|
10
|
+
2. Reconfigures jetty
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def banner
|
|
14
|
+
say_status("warning", "GENERATING CURATION_CONCERNS FULL-TEXT", :yellow)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Copy CurationConcerns's solrconfig into the dir from which the jetty:config task pulls
|
|
18
|
+
# CurationConcerns's solrconfig includes full-text extraction
|
|
19
|
+
def copy_solr_config
|
|
20
|
+
src = File.join(__FILE__, '..', '..', '..', '..', '..', '..', 'solr_conf', 'conf', 'solrconfig.xml')
|
|
21
|
+
copy_file File.expand_path(src), 'solr_conf/conf/solrconfig.xml', force: true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Copy config, schema, and jars into jetty dir if it exists
|
|
25
|
+
def reconfigure_jetty
|
|
26
|
+
rake "curation_concerns:jetty:config" if File.directory?('jetty')
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require_relative 'abstract_migration_generator'
|
|
2
|
+
|
|
3
|
+
class CurationConcerns::Models::InstallGenerator < CurationConcerns::Models::AbstractMigrationGenerator
|
|
4
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
5
|
+
argument :model_name, type: :string , default: "user"
|
|
6
|
+
desc """
|
|
7
|
+
This generator makes the following changes to your application:
|
|
8
|
+
1. Creates several database migrations if they do not exist in /db/migrate
|
|
9
|
+
2. Creates the curation_concerns.rb configuration file and several others
|
|
10
|
+
3. Creates the generic_file.rb, generic_work.rb and collection.rb models
|
|
11
|
+
4. Runs full-text generator
|
|
12
|
+
"""
|
|
13
|
+
def banner
|
|
14
|
+
say_status("warning", "GENERATING CURATION_CONCERNS MODELS", :yellow)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Setup the database migrations
|
|
18
|
+
def copy_migrations
|
|
19
|
+
[
|
|
20
|
+
"create_version_committers.rb",
|
|
21
|
+
"create_checksum_audit_logs.rb"#,
|
|
22
|
+
].each do |file|
|
|
23
|
+
better_migration_template file
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Add behaviors to the user model
|
|
28
|
+
def inject_curation_concerns_user_behavior
|
|
29
|
+
file_path = "app/models/#{model_name.underscore}.rb"
|
|
30
|
+
if File.exists?(file_path)
|
|
31
|
+
inject_into_file file_path, after: /include Hydra\:\:User.*$/ do
|
|
32
|
+
"\n # Connects this user object to Curation Concerns behaviors." +
|
|
33
|
+
"\n include CurationConcerns::User\n"
|
|
34
|
+
end
|
|
35
|
+
else
|
|
36
|
+
puts " \e[31mFailure\e[0m CurationConcerns requires a user object. This generators 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 curation_concerns client"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def create_configuration_files
|
|
41
|
+
append_file 'config/initializers/mime_types.rb',
|
|
42
|
+
"\nMime::Type.register 'application/x-endnote-refer', :endnote", {verbose: false }
|
|
43
|
+
copy_file 'config/curation_concerns.rb', 'config/initializers/curation_concerns.rb'
|
|
44
|
+
copy_file 'config/redis.yml', 'config/redis.yml'
|
|
45
|
+
copy_file 'config/resque-pool.yml', 'config/resque-pool.yml'
|
|
46
|
+
copy_file 'config/redis_config.rb', 'config/initializers/redis_config.rb'
|
|
47
|
+
copy_file 'config/resque_admin.rb', 'config/initializers/resque_admin.rb'
|
|
48
|
+
copy_file 'config/resque_config.rb', 'config/initializers/resque_config.rb'
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def create_collection
|
|
52
|
+
copy_file 'app/models/collection.rb', 'app/models/collection.rb'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def create_generic_file
|
|
56
|
+
copy_file 'app/models/generic_file.rb', 'app/models/generic_file.rb'
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Sets up full-text indexing (Solr config + jars)
|
|
60
|
+
def full_text_indexing
|
|
61
|
+
generate "curation_concerns:models:fulltext"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Adds clamav initializtion
|
|
65
|
+
def clamav
|
|
66
|
+
generate 'curation_concerns:models:clamav'
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ClamAV.instance.loaddb() if defined? ClamAV
|