rivendell-import 0.0.1

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 (67) hide show
  1. data/.gitignore +21 -0
  2. data/Gemfile +11 -0
  3. data/Guardfile +14 -0
  4. data/LICENSE +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +4 -0
  7. data/bin/rivendell-import +6 -0
  8. data/db/migrate/20120920712200_create_tasks.rb +21 -0
  9. data/db/migrate/20120927194300_create_notifiers.rb +14 -0
  10. data/db/migrate/20120927203600_create_notifications.rb +14 -0
  11. data/examples/.gitignore +2 -0
  12. data/examples/config.rb +31 -0
  13. data/features/manage_cart_attributes.feature +20 -0
  14. data/features/manage_file_matching.feature +44 -0
  15. data/features/step_definitions/import_steps.rb +38 -0
  16. data/features/support/env.rb +19 -0
  17. data/features/support/mock_xport.rb +34 -0
  18. data/lib/rivendell/import.rb +48 -0
  19. data/lib/rivendell/import/base.rb +57 -0
  20. data/lib/rivendell/import/cart.rb +67 -0
  21. data/lib/rivendell/import/carts_cache.rb +58 -0
  22. data/lib/rivendell/import/cli.rb +90 -0
  23. data/lib/rivendell/import/config.rb +13 -0
  24. data/lib/rivendell/import/context.rb +28 -0
  25. data/lib/rivendell/import/cut.rb +33 -0
  26. data/lib/rivendell/import/file.rb +57 -0
  27. data/lib/rivendell/import/notification.rb +16 -0
  28. data/lib/rivendell/import/notifier/base.rb +89 -0
  29. data/lib/rivendell/import/notifier/mail-body.erb +8 -0
  30. data/lib/rivendell/import/notifier/mail-subject.erb +11 -0
  31. data/lib/rivendell/import/notifier/mail.rb +104 -0
  32. data/lib/rivendell/import/notifiers.rb +24 -0
  33. data/lib/rivendell/import/task.rb +80 -0
  34. data/lib/rivendell/import/tasking/cart.rb +25 -0
  35. data/lib/rivendell/import/tasking/destination.rb +28 -0
  36. data/lib/rivendell/import/tasking/file.rb +20 -0
  37. data/lib/rivendell/import/tasking/status.rb +29 -0
  38. data/lib/rivendell/import/tasking/tags.rb +27 -0
  39. data/lib/rivendell/import/tasks.rb +23 -0
  40. data/lib/rivendell/import/version.rb +5 -0
  41. data/lib/rivendell/import/worker.rb +34 -0
  42. data/rivendell-import.gemspec +37 -0
  43. data/spec/fixtures/mail-body.erb +5 -0
  44. data/spec/rivendell/import/base_spec.rb +125 -0
  45. data/spec/rivendell/import/cart_spec.rb +132 -0
  46. data/spec/rivendell/import/carts_cache_spec.rb +110 -0
  47. data/spec/rivendell/import/cli_spec.rb +149 -0
  48. data/spec/rivendell/import/config_spec.rb +16 -0
  49. data/spec/rivendell/import/context_spec.rb +19 -0
  50. data/spec/rivendell/import/file_spec.rb +63 -0
  51. data/spec/rivendell/import/notifier/base_spec.rb +63 -0
  52. data/spec/rivendell/import/notifier/mail_spec.rb +110 -0
  53. data/spec/rivendell/import/task_spec.rb +217 -0
  54. data/spec/rivendell/import/tasks_spec.rb +30 -0
  55. data/spec/rivendell/import/worker_spec.rb +25 -0
  56. data/spec/rivendell/import_spec.rb +32 -0
  57. data/spec/spec_helper.rb +15 -0
  58. data/spec/support/database_cleaner.rb +17 -0
  59. data/spec/support/fixtures.rb +3 -0
  60. data/spec/support/mail.rb +3 -0
  61. data/spec/support/test_notifier.rb +15 -0
  62. data/tasks/ci.rake +2 -0
  63. data/tasks/cucumber.rake +4 -0
  64. data/tasks/database.rake +11 -0
  65. data/tasks/rdoc.rake +16 -0
  66. data/tasks/rspec.rake +2 -0
  67. metadata +399 -0
@@ -0,0 +1,8 @@
1
+ <% tasks.each do |task| -%>
2
+ <%= task.file %>
3
+ <% if task.status.completed? -%>
4
+ imported in <%= task.destination %>
5
+ <% else -%>
6
+ failed
7
+ <% end -%>
8
+ <% end %>
@@ -0,0 +1,11 @@
1
+ [Rivendell Import]
2
+ <% if many? %>
3
+ <%= tasks.count %> task(s) completed
4
+ <% else %>
5
+ <% task = tasks.first %>
6
+ <% if task.status.completed? %>
7
+ <%= task.destination %> imported
8
+ <% else %>
9
+ <%= task.file.name %> failed
10
+ <% end %>
11
+ <% end %>
@@ -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,5 @@
1
+ module Rivendell
2
+ module Import
3
+ VERSION = "0.0.1"
4
+ end
5
+ 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