rivendell-import 0.0.1

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