rivendell-import 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +21 -0
- data/Gemfile +11 -0
- data/Guardfile +14 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +4 -0
- data/bin/rivendell-import +6 -0
- data/db/migrate/20120920712200_create_tasks.rb +21 -0
- data/db/migrate/20120927194300_create_notifiers.rb +14 -0
- data/db/migrate/20120927203600_create_notifications.rb +14 -0
- data/examples/.gitignore +2 -0
- data/examples/config.rb +31 -0
- data/features/manage_cart_attributes.feature +20 -0
- data/features/manage_file_matching.feature +44 -0
- data/features/step_definitions/import_steps.rb +38 -0
- data/features/support/env.rb +19 -0
- data/features/support/mock_xport.rb +34 -0
- data/lib/rivendell/import.rb +48 -0
- data/lib/rivendell/import/base.rb +57 -0
- data/lib/rivendell/import/cart.rb +67 -0
- data/lib/rivendell/import/carts_cache.rb +58 -0
- data/lib/rivendell/import/cli.rb +90 -0
- data/lib/rivendell/import/config.rb +13 -0
- data/lib/rivendell/import/context.rb +28 -0
- data/lib/rivendell/import/cut.rb +33 -0
- data/lib/rivendell/import/file.rb +57 -0
- data/lib/rivendell/import/notification.rb +16 -0
- data/lib/rivendell/import/notifier/base.rb +89 -0
- data/lib/rivendell/import/notifier/mail-body.erb +8 -0
- data/lib/rivendell/import/notifier/mail-subject.erb +11 -0
- data/lib/rivendell/import/notifier/mail.rb +104 -0
- data/lib/rivendell/import/notifiers.rb +24 -0
- data/lib/rivendell/import/task.rb +80 -0
- data/lib/rivendell/import/tasking/cart.rb +25 -0
- data/lib/rivendell/import/tasking/destination.rb +28 -0
- data/lib/rivendell/import/tasking/file.rb +20 -0
- data/lib/rivendell/import/tasking/status.rb +29 -0
- data/lib/rivendell/import/tasking/tags.rb +27 -0
- data/lib/rivendell/import/tasks.rb +23 -0
- data/lib/rivendell/import/version.rb +5 -0
- data/lib/rivendell/import/worker.rb +34 -0
- data/rivendell-import.gemspec +37 -0
- data/spec/fixtures/mail-body.erb +5 -0
- data/spec/rivendell/import/base_spec.rb +125 -0
- data/spec/rivendell/import/cart_spec.rb +132 -0
- data/spec/rivendell/import/carts_cache_spec.rb +110 -0
- data/spec/rivendell/import/cli_spec.rb +149 -0
- data/spec/rivendell/import/config_spec.rb +16 -0
- data/spec/rivendell/import/context_spec.rb +19 -0
- data/spec/rivendell/import/file_spec.rb +63 -0
- data/spec/rivendell/import/notifier/base_spec.rb +63 -0
- data/spec/rivendell/import/notifier/mail_spec.rb +110 -0
- data/spec/rivendell/import/task_spec.rb +217 -0
- data/spec/rivendell/import/tasks_spec.rb +30 -0
- data/spec/rivendell/import/worker_spec.rb +25 -0
- data/spec/rivendell/import_spec.rb +32 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/database_cleaner.rb +17 -0
- data/spec/support/fixtures.rb +3 -0
- data/spec/support/mail.rb +3 -0
- data/spec/support/test_notifier.rb +15 -0
- data/tasks/ci.rake +2 -0
- data/tasks/cucumber.rake +4 -0
- data/tasks/database.rake +11 -0
- data/tasks/rdoc.rake +16 -0
- data/tasks/rspec.rake +2 -0
- metadata +399 -0
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'mail'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
module Rivendell::Import::Notifier
|
5
|
+
class Mail < Rivendell::Import::Notifier::Base
|
6
|
+
|
7
|
+
@@from = nil
|
8
|
+
cattr_accessor :from
|
9
|
+
|
10
|
+
attr_accessor :from, :to, :subject, :body
|
11
|
+
|
12
|
+
def subject
|
13
|
+
@subject ||= File.expand_path("../mail-subject.erb", __FILE__)
|
14
|
+
end
|
15
|
+
|
16
|
+
def body
|
17
|
+
@body ||= File.expand_path("../mail-body.erb", __FILE__)
|
18
|
+
end
|
19
|
+
|
20
|
+
def from
|
21
|
+
@from ||= self.class.from
|
22
|
+
end
|
23
|
+
|
24
|
+
def notify!(tasks)
|
25
|
+
create_message(tasks).deliver!
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_message(tasks)
|
29
|
+
Message.new(tasks).tap do |mail|
|
30
|
+
mail.from = from
|
31
|
+
mail.to = to
|
32
|
+
mail.subject = template(subject)
|
33
|
+
mail.body = template(body)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Message
|
38
|
+
|
39
|
+
attr_reader :tasks
|
40
|
+
attr_accessor :from, :to, :subject, :body
|
41
|
+
|
42
|
+
def initialize(tasks)
|
43
|
+
@tasks = tasks
|
44
|
+
end
|
45
|
+
|
46
|
+
def completed
|
47
|
+
tasks.select { |task| task.status.completed? }
|
48
|
+
end
|
49
|
+
|
50
|
+
def failed
|
51
|
+
tasks.select { |task| task.status.failed? }
|
52
|
+
end
|
53
|
+
|
54
|
+
def failed?
|
55
|
+
failed.present?
|
56
|
+
end
|
57
|
+
|
58
|
+
delegate :many?, :to => :tasks
|
59
|
+
|
60
|
+
def mail
|
61
|
+
::Mail.new.tap do |mail|
|
62
|
+
mail.from = from
|
63
|
+
mail.to = to
|
64
|
+
mail.subject = strip(render(subject))
|
65
|
+
mail.body = render(body)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def deliver!
|
70
|
+
mail.deliver!
|
71
|
+
end
|
72
|
+
|
73
|
+
def render(template)
|
74
|
+
ERB.new(template, nil, '%<>-').result(binding)
|
75
|
+
end
|
76
|
+
|
77
|
+
def strip(text)
|
78
|
+
text.strip.gsub(/\n[ ]*/m,"")
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
# def valid?
|
84
|
+
# [from, to, subject, body].all?(&:present?)
|
85
|
+
# end
|
86
|
+
|
87
|
+
def parameters
|
88
|
+
%w{from to subject body}.inject({}) do |map, attribute|
|
89
|
+
value = send attribute
|
90
|
+
map[attribute] = value if value
|
91
|
+
map
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def template(definition)
|
96
|
+
if File.exists?(definition)
|
97
|
+
File.read definition
|
98
|
+
else
|
99
|
+
definition
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Rivendell::Import
|
2
|
+
class Notifiers
|
3
|
+
|
4
|
+
attr_reader :import, :notifiers
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@import = import
|
8
|
+
end
|
9
|
+
|
10
|
+
def push(notifier)
|
11
|
+
notifiers << notifier
|
12
|
+
end
|
13
|
+
|
14
|
+
def notify!
|
15
|
+
notified_tasks = waiting_tasks
|
16
|
+
@waiting_tasks = []
|
17
|
+
|
18
|
+
notifiers.each do |notifier|
|
19
|
+
notifier.notify notified_tasks
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'rivendell/import/tasking/file'
|
2
|
+
require 'rivendell/import/tasking/tags'
|
3
|
+
require 'rivendell/import/tasking/cart'
|
4
|
+
require 'rivendell/import/tasking/status'
|
5
|
+
require 'rivendell/import/tasking/destination'
|
6
|
+
|
7
|
+
module Rivendell::Import
|
8
|
+
class Task < ActiveRecord::Base
|
9
|
+
include Rivendell::Import::Tasking::File
|
10
|
+
include Rivendell::Import::Tasking::Tags
|
11
|
+
include Rivendell::Import::Tasking::Cart
|
12
|
+
include Rivendell::Import::Tasking::Status
|
13
|
+
include Rivendell::Import::Tasking::Destination
|
14
|
+
|
15
|
+
def self.pending
|
16
|
+
where :status => "pending"
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.ran
|
20
|
+
where :status => %w{completed failed}
|
21
|
+
end
|
22
|
+
|
23
|
+
def ran?
|
24
|
+
status.completed? or status.failed?
|
25
|
+
end
|
26
|
+
|
27
|
+
def xport
|
28
|
+
@xport ||= Rivendell::API::Xport.new
|
29
|
+
end
|
30
|
+
|
31
|
+
def prepare(&block)
|
32
|
+
begin
|
33
|
+
Context.new(self).run(&block)
|
34
|
+
rescue => e
|
35
|
+
logger.error "Task preparation failed : #{e}"
|
36
|
+
end
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def logger
|
41
|
+
Rivendell::Import.logger
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
"Import '#{file}' in #{destination}"
|
46
|
+
end
|
47
|
+
|
48
|
+
has_many :notifications
|
49
|
+
has_many :notifiers, :through => :notifications
|
50
|
+
|
51
|
+
def notify!
|
52
|
+
notifiers.each do |notifier|
|
53
|
+
notifier.notify
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def run
|
58
|
+
logger.debug "Run #{self.inspect}"
|
59
|
+
change_status! :running
|
60
|
+
|
61
|
+
reset_destination!
|
62
|
+
|
63
|
+
cart.create
|
64
|
+
cart.import file
|
65
|
+
cart.update
|
66
|
+
|
67
|
+
save!
|
68
|
+
change_status! :completed
|
69
|
+
|
70
|
+
logger.info "Imported Cart #{cart.number}"
|
71
|
+
rescue Exception => e
|
72
|
+
logger.error "Task failed : #{e}"
|
73
|
+
ensure
|
74
|
+
unless status.completed?
|
75
|
+
change_status! :failed
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Rivendell::Import::Tasking
|
2
|
+
module Cart
|
3
|
+
|
4
|
+
def raw_cart
|
5
|
+
read_attribute :cart
|
6
|
+
end
|
7
|
+
|
8
|
+
def cart
|
9
|
+
@cast ||= Rivendell::Import::Cart.new(self).tap do |cart|
|
10
|
+
cart.from_json raw_cart if raw_cart
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def write_cart
|
15
|
+
write_attribute :cart, (cart.present? ? cart.to_json : nil)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.included(base)
|
19
|
+
base.class_eval do
|
20
|
+
before_save :write_cart
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Rivendell::Import::Tasking
|
2
|
+
module Destination
|
3
|
+
|
4
|
+
def destination
|
5
|
+
read_attribute(:destination) or
|
6
|
+
write_attribute(:destination, calculate_destination)
|
7
|
+
end
|
8
|
+
|
9
|
+
def reset_destination!
|
10
|
+
write_attribute :destination, nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.included(base)
|
14
|
+
base.class_eval do
|
15
|
+
before_save :destination, :on => :create
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def calculate_destination
|
20
|
+
if cart.number
|
21
|
+
"Cart #{cart.number}"
|
22
|
+
elsif cart.group
|
23
|
+
"Cart in group #{cart.group}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Rivendell::Import::Tasking
|
2
|
+
module File
|
3
|
+
def file=(file)
|
4
|
+
if file
|
5
|
+
@file = file
|
6
|
+
|
7
|
+
self.file_name = file.name
|
8
|
+
self.file_path = file.path
|
9
|
+
else
|
10
|
+
@file = nil
|
11
|
+
|
12
|
+
self.file_name = self.file_path = nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def file
|
17
|
+
@file ||= Rivendell::Import::File.new(file_name, :path => file_path)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Rivendell::Import::Tasking
|
2
|
+
module Status
|
3
|
+
|
4
|
+
def define_default_status
|
5
|
+
self.status ||= "pending"
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.included(base)
|
9
|
+
base.class_eval do
|
10
|
+
after_initialize :define_default_status
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def raw_status
|
15
|
+
read_attribute(:status)
|
16
|
+
end
|
17
|
+
|
18
|
+
def status
|
19
|
+
ActiveSupport::StringInquirer.new(raw_status) if raw_status
|
20
|
+
end
|
21
|
+
|
22
|
+
def change_status!(status)
|
23
|
+
logger.debug "Change status to #{status}"
|
24
|
+
update_attribute :status, status.to_s
|
25
|
+
notify! if ran?
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Rivendell::Import::Tasking
|
2
|
+
module Tags
|
3
|
+
|
4
|
+
def raw_tags
|
5
|
+
read_attribute :tags
|
6
|
+
end
|
7
|
+
|
8
|
+
def tags
|
9
|
+
@tags ||= (raw_tags ? raw_tags.split(",") : [])
|
10
|
+
end
|
11
|
+
|
12
|
+
def tag(tag)
|
13
|
+
self.tags << tag
|
14
|
+
end
|
15
|
+
|
16
|
+
def write_tags
|
17
|
+
write_attribute :tags, tags.join(',') if @tags
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.included(base)
|
21
|
+
base.class_eval do
|
22
|
+
before_save :write_tags
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Rivendell::Import
|
2
|
+
class Tasks
|
3
|
+
|
4
|
+
def pending?
|
5
|
+
not Task.pending.empty?
|
6
|
+
end
|
7
|
+
|
8
|
+
def pop
|
9
|
+
Task.pending.first
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
Task.pending.find_each(&:run)
|
14
|
+
end
|
15
|
+
|
16
|
+
def create(file, &block)
|
17
|
+
Rivendell::Import::Task.create({:file => file}, {}, &block).tap do |task|
|
18
|
+
Rivendell::Import.logger.debug "Created task #{task.inspect}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Rivendell::Import
|
2
|
+
class Worker
|
3
|
+
|
4
|
+
attr_reader :import
|
5
|
+
|
6
|
+
def initialize(import)
|
7
|
+
@import = import
|
8
|
+
end
|
9
|
+
|
10
|
+
def start
|
11
|
+
Thread.new do
|
12
|
+
Rivendell::Import.logger.debug "Start Worker"
|
13
|
+
run
|
14
|
+
end
|
15
|
+
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
loop do
|
21
|
+
task = import.tasks.pop
|
22
|
+
if task
|
23
|
+
task.run
|
24
|
+
else
|
25
|
+
# Rivendell::Import.logger.debug "No pending task, sleep 10s"
|
26
|
+
sleep 10
|
27
|
+
end
|
28
|
+
end
|
29
|
+
rescue => e
|
30
|
+
Rivendell::Import.logger.error "Worker failed : #{e}"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/rivendell/import/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Alban Peignier"]
|
6
|
+
gem.email = ["alban@tryphon.eu"]
|
7
|
+
gem.description = %q{Import sound in our Rivendell system}
|
8
|
+
gem.summary = %q{Import engine for Rivendell}
|
9
|
+
gem.homepage = "http://wiki.tryphon.eu/rivendell-import/"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "rivendell-import"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Rivendell::Import::VERSION
|
17
|
+
|
18
|
+
gem.add_runtime_dependency 'listen'
|
19
|
+
gem.add_runtime_dependency 'httmultiparty'
|
20
|
+
gem.add_runtime_dependency 'rivendell-api', '~> 0.0.2'
|
21
|
+
gem.add_runtime_dependency 'trollop'
|
22
|
+
gem.add_runtime_dependency 'activerecord', '~> 3.2.8'
|
23
|
+
gem.add_runtime_dependency 'activesupport', '~> 3.2.8'
|
24
|
+
gem.add_runtime_dependency 'mail'
|
25
|
+
gem.add_runtime_dependency 'sqlite3'
|
26
|
+
|
27
|
+
gem.add_development_dependency "simplecov"
|
28
|
+
gem.add_development_dependency "rspec"
|
29
|
+
gem.add_development_dependency "guard"
|
30
|
+
gem.add_development_dependency "guard-rspec"
|
31
|
+
gem.add_development_dependency "guard-cucumber"
|
32
|
+
gem.add_development_dependency "rake"
|
33
|
+
gem.add_development_dependency "cucumber"
|
34
|
+
gem.add_development_dependency "database_cleaner"
|
35
|
+
# gem.add_development_dependency "remarkable_activerecord"
|
36
|
+
|
37
|
+
end
|