voicemail 0.2.0 → 1.0.0.beta
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 +4 -4
- data/CHANGELOG.md +44 -0
- data/README.md +57 -2
- data/lib/voicemail.rb +15 -8
- data/lib/voicemail/{application_controller.rb → call_controllers/application_controller.rb} +14 -1
- data/lib/voicemail/call_controllers/authentication_controller.rb +60 -0
- data/lib/voicemail/call_controllers/mailbox_controller.rb +46 -0
- data/lib/voicemail/{mailbox_main_menu_controller.rb → call_controllers/mailbox_main_menu_controller.rb} +9 -4
- data/lib/voicemail/call_controllers/mailbox_messages_controller.rb +48 -0
- data/lib/voicemail/{mailbox_play_message_controller.rb → call_controllers/mailbox_play_message_controller.rb} +26 -10
- data/lib/voicemail/call_controllers/mailbox_play_message_intro_controller.rb +72 -0
- data/lib/voicemail/{mailbox_set_greeting_controller.rb → call_controllers/mailbox_set_greeting_controller.rb} +2 -2
- data/lib/voicemail/{mailbox_set_pin_controller.rb → call_controllers/mailbox_set_pin_controller.rb} +0 -0
- data/lib/voicemail/call_controllers/voicemail_controller.rb +57 -0
- data/lib/voicemail/localization_loader.rb +28 -0
- data/lib/voicemail/matcher.rb +14 -0
- data/lib/voicemail/plugin.rb +40 -15
- data/lib/voicemail/storage_pstore.rb +49 -2
- data/lib/voicemail/version.rb +1 -1
- data/spec/voicemail/call_controllers/application_controller_spec.rb +31 -0
- data/spec/voicemail/call_controllers/authentication_controller_spec.rb +59 -0
- data/spec/voicemail/call_controllers/mailbox_controller_spec.rb +107 -0
- data/spec/voicemail/{mailbox_main_menu_controller_spec.rb → call_controllers/mailbox_main_menu_controller_spec.rb} +9 -2
- data/spec/voicemail/call_controllers/mailbox_messages_controller_spec.rb +110 -0
- data/spec/voicemail/call_controllers/mailbox_play_message_controller_spec.rb +97 -0
- data/spec/voicemail/call_controllers/mailbox_play_message_intro_controller_spec.rb +81 -0
- data/spec/voicemail/{mailbox_set_greeting_controller_spec.rb → call_controllers/mailbox_set_greeting_controller_spec.rb} +24 -6
- data/spec/voicemail/{mailbox_set_pin_controller_spec.rb → call_controllers/mailbox_set_pin_controller_spec.rb} +0 -0
- data/spec/voicemail/call_controllers/voicemail_controller_spec.rb +97 -0
- data/spec/voicemail/localization_loader_spec.rb +21 -0
- data/spec/voicemail/storage_pstore_spec.rb +64 -2
- data/templates/en.yml +67 -0
- data/voicemail.gemspec +2 -2
- metadata +42 -26
- data/lib/voicemail/mailbox_controller.rb +0 -56
- data/lib/voicemail/mailbox_messages_controller.rb +0 -55
- data/lib/voicemail/voicemail_controller.rb +0 -33
- data/spec/voicemail/mailbox_controller_spec.rb +0 -79
- data/spec/voicemail/mailbox_messages_controller_spec.rb +0 -71
- data/spec/voicemail/mailbox_play_message_controller_spec.rb +0 -70
- data/spec/voicemail/voicemail_controller_spec.rb +0 -76
@@ -26,10 +26,17 @@ describe Voicemail::MailboxMainMenuController do
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
describe "#
|
29
|
+
describe "#listen_to_new_messages" do
|
30
30
|
it "invokes MailboxMessagesController" do
|
31
31
|
should_invoke Voicemail::MailboxMessagesController, mailbox: mailbox[:id]
|
32
|
-
controller.
|
32
|
+
controller.listen_to_new_messages
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#listen_to_saved_messages" do
|
37
|
+
it "invokes MailboxMessagesController" do
|
38
|
+
should_invoke Voicemail::MailboxMessagesController, mailbox: mailbox[:id], new_or_saved: :saved
|
39
|
+
controller.listen_to_saved_messages
|
33
40
|
end
|
34
41
|
end
|
35
42
|
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Voicemail
|
4
|
+
describe MailboxMessagesController do
|
5
|
+
include VoicemailControllerSpecHelper
|
6
|
+
|
7
|
+
let(:call) { flexmock('Call') }
|
8
|
+
let(:config) { Voicemail::Plugin.config }
|
9
|
+
let(:metadata) { {mailbox: '100', new_or_saved: message_type} }
|
10
|
+
|
11
|
+
let(:mailbox) do
|
12
|
+
{
|
13
|
+
:id => 100,
|
14
|
+
:pin => 1234,
|
15
|
+
:greeting_message => nil,
|
16
|
+
:send_email => true,
|
17
|
+
:email_address => "lpradovera@mojolingo.com"
|
18
|
+
}
|
19
|
+
end
|
20
|
+
let(:message) do
|
21
|
+
{
|
22
|
+
:id => 123,
|
23
|
+
:from => "+39-335135335",
|
24
|
+
:received => Time.local(2012, 5, 1, 9, 0, 0),
|
25
|
+
:uri => "file:///path/to/file.mp3"
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:storage_instance) { flexmock('StorageInstance') }
|
30
|
+
|
31
|
+
let(:controller){ Voicemail::MailboxMessagesController.new call, metadata }
|
32
|
+
subject { flexmock controller }
|
33
|
+
|
34
|
+
before(:each) do
|
35
|
+
storage_instance.should_receive(:get_mailbox).with(metadata[:mailbox]).and_return(mailbox)
|
36
|
+
flexmock(Storage).should_receive(:instance).and_return(storage_instance)
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
context "with new messages" do
|
41
|
+
let(:message_type) { :new }
|
42
|
+
|
43
|
+
describe "#message_loop" do
|
44
|
+
after { controller.message_loop }
|
45
|
+
|
46
|
+
it "calls #next_message if there are new messages" do
|
47
|
+
storage_instance.should_receive(:count_new_messages).once.with(mailbox[:id]).and_return(3)
|
48
|
+
subject.should_receive(:next_message).once
|
49
|
+
end
|
50
|
+
|
51
|
+
it "plays a message and goes to the main menu if there are no new messages" do
|
52
|
+
storage_instance.should_receive(:count_new_messages).once.with(mailbox[:id]).and_return(0)
|
53
|
+
subject.should_receive(:play).with(config.messages.no_new_messages).once
|
54
|
+
subject.should_receive(:main_menu).once
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#next_message" do
|
59
|
+
it "gets the next message and calls #handle_message" do
|
60
|
+
storage_instance.should_receive(:next_new_message).once.with(mailbox[:id]).and_return(message)
|
61
|
+
subject.should_receive(:handle_message).once.with(message)
|
62
|
+
subject.should_receive(:message_loop).once
|
63
|
+
controller.next_message
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#handle_message" do
|
68
|
+
it "invokes MailboxPlayMessageController" do
|
69
|
+
should_invoke Voicemail::MailboxPlayMessageController, message: message, mailbox: mailbox[:id], new_or_saved: :new, storage: storage_instance
|
70
|
+
controller.handle_message message
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "with saved messages" do
|
76
|
+
let(:message_type) { :saved }
|
77
|
+
|
78
|
+
describe "#message_loop" do
|
79
|
+
after { controller.message_loop }
|
80
|
+
|
81
|
+
it "calls #next_message if there are saved messages" do
|
82
|
+
storage_instance.should_receive(:count_saved_messages).once.with(mailbox[:id]).and_return(3)
|
83
|
+
subject.should_receive(:next_message).once
|
84
|
+
end
|
85
|
+
|
86
|
+
it "plays a message and goes to the main menu if there are no saved messages" do
|
87
|
+
storage_instance.should_receive(:count_saved_messages).once.with(mailbox[:id]).and_return(0)
|
88
|
+
subject.should_receive(:play).with(config.messages.no_saved_messages).once
|
89
|
+
subject.should_receive(:main_menu).once
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "#next_message" do
|
94
|
+
it "gets the next message and calls #handle_message" do
|
95
|
+
storage_instance.should_receive(:next_saved_message).once.with(mailbox[:id]).and_return(message)
|
96
|
+
subject.should_receive(:handle_message).once.with(message)
|
97
|
+
subject.should_receive(:message_loop).once
|
98
|
+
controller.next_message
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "#handle_message" do
|
103
|
+
it "invokes MailboxPlayMessageController" do
|
104
|
+
should_invoke Voicemail::MailboxPlayMessageController, message: message, mailbox: mailbox[:id], new_or_saved: :saved, storage: storage_instance
|
105
|
+
controller.handle_message message
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Voicemail::MailboxPlayMessageController do
|
4
|
+
include VoicemailControllerSpecHelper
|
5
|
+
|
6
|
+
let(:message) do
|
7
|
+
{
|
8
|
+
id: 123,
|
9
|
+
from: "+39-335135335",
|
10
|
+
received: Time.local(2012, 5, 1, 9, 0, 0),
|
11
|
+
uri: "file:///path/to/file.mp3"
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#archive_or_unarchive_message" do
|
16
|
+
|
17
|
+
after { controller.archive_or_unarchive_message }
|
18
|
+
|
19
|
+
context "with a new message" do
|
20
|
+
before { subject.new_or_saved = :new }
|
21
|
+
|
22
|
+
it "archives the message" do
|
23
|
+
subject.should_receive(:current_message).once.and_return message
|
24
|
+
storage_instance.should_receive(:archive_message).once.with mailbox[:id], message[:id]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "with a saved message" do
|
29
|
+
before { subject.new_or_saved = :saved }
|
30
|
+
|
31
|
+
it "unarchives the message" do
|
32
|
+
subject.should_receive(:current_message).once.and_return message
|
33
|
+
storage_instance.should_receive(:unarchive_message).once.with mailbox[:id], message[:id]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#delete_message" do
|
39
|
+
it "deletes the message" do
|
40
|
+
subject.should_receive(:current_message).once.and_return(message)
|
41
|
+
storage_instance.should_receive(:delete_message).once.with(mailbox[:id], message[:id])
|
42
|
+
controller.delete_message
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#intro_message" do
|
47
|
+
it "plays the message introduction" do
|
48
|
+
subject.should_receive(:current_message).once.and_return message
|
49
|
+
should_invoke Voicemail::MailboxPlayMessageIntroController, message: message, mailbox: 100, storage: storage_instance
|
50
|
+
controller.intro_message
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#play_message" do
|
55
|
+
after { subject.play_message }
|
56
|
+
|
57
|
+
context "with a new message" do
|
58
|
+
before { subject.new_or_saved = :new }
|
59
|
+
|
60
|
+
it "plays the message, followed by the new message menu" do
|
61
|
+
subject.should_receive(:current_message).once.and_return message
|
62
|
+
subject.should_receive(:menu).once.with message[:uri], config.messages.menu_new,
|
63
|
+
{ timeout: config.menu_timeout, tries: config.menu_tries }, Proc
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "with a saved message" do
|
68
|
+
before { subject.new_or_saved = :saved }
|
69
|
+
|
70
|
+
it "plays the message, followed by the saved message menu" do
|
71
|
+
subject.should_receive(:current_message).once.and_return message
|
72
|
+
subject.should_receive(:menu).once.with message[:uri], config.messages.menu_saved,
|
73
|
+
{ timeout: config.menu_timeout, tries: config.menu_tries }, Proc
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "#load_message" do
|
79
|
+
|
80
|
+
context "with a message" do
|
81
|
+
let(:metadata) { {message: "foo"} }
|
82
|
+
|
83
|
+
it "loads the messge" do
|
84
|
+
subject.load_message
|
85
|
+
subject.current_message.should == "foo"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "with no message passed" do
|
90
|
+
let(:metadata) { {message: nil} }
|
91
|
+
|
92
|
+
it "raises an error" do
|
93
|
+
expect { subject.load_message }.to raise_error ArgumentError
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Voicemail::MailboxPlayMessageIntroController do
|
4
|
+
include VoicemailControllerSpecHelper
|
5
|
+
|
6
|
+
let(:some_time) { Time.local 2012, 5, 1, 9, 0, 0 }
|
7
|
+
let(:message) do
|
8
|
+
{
|
9
|
+
id: 123,
|
10
|
+
from: "+123",
|
11
|
+
received: some_time,
|
12
|
+
uri: "file:///path/to/file.mp3"
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
before do
|
17
|
+
config.numeric_method = numeric_method
|
18
|
+
subject.should_receive(:current_message).and_return message
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#intro_message" do
|
22
|
+
|
23
|
+
after { subject.intro_message }
|
24
|
+
|
25
|
+
context "with the default mode" do
|
26
|
+
let(:numeric_method) { :play_numeric}
|
27
|
+
|
28
|
+
it "plays the message introduction" do
|
29
|
+
should_play config.messages.message_received_on
|
30
|
+
subject.should_receive(:play_time).with some_time, format: config.datetime_format
|
31
|
+
|
32
|
+
should_play config.messages.from
|
33
|
+
subject.should_receive(:say_characters).with "123"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "with ahnsay" do
|
38
|
+
let(:numeric_method) { :ahn_say }
|
39
|
+
|
40
|
+
it "plays the message introduction" do
|
41
|
+
should_play config.messages.message_received_on
|
42
|
+
subject.should_receive(:sounds_for_time).with(some_time, format: config.datetime_format).and_return ["timesounds", ".wav"]
|
43
|
+
should_play "timesounds", ".wav"
|
44
|
+
|
45
|
+
should_play config.messages.from
|
46
|
+
subject.should_receive(:sounds_for_digits).with("123").and_return ["digit1.wav", "digit2.wav"]
|
47
|
+
should_play "digit1.wav", "digit2.wav"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "with i18n_string" do
|
52
|
+
let(:numeric_method) { :i18n_string }
|
53
|
+
|
54
|
+
it "plays the message introduction" do
|
55
|
+
flexmock(I18n).should_receive(:localize).with(some_time).and_return "some time"
|
56
|
+
flexmock(I18n).should_receive(:t).with("voicemail.messages.message_received_on_x", received_on: "some time").and_return "Message received on some time. "
|
57
|
+
flexmock(I18n).should_receive(:t).with("numbers.1").and_return "one "
|
58
|
+
flexmock(I18n).should_receive(:t).with("numbers.2").and_return "two "
|
59
|
+
flexmock(I18n).should_receive(:t).with("numbers.3").and_return "three"
|
60
|
+
flexmock(I18n).should_receive(:t).with("voicemail.messages.message_received_from_x", from: "one two three").and_return "Message received from one two three"
|
61
|
+
|
62
|
+
should_play "Message received on some time. "
|
63
|
+
should_play "Message received from one two three"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#play_from_message with i18n_string and missing digit translations" do
|
69
|
+
let(:numeric_method) { :i18n_string }
|
70
|
+
|
71
|
+
after { subject.play_from_message }
|
72
|
+
|
73
|
+
it "falls back sanely" do
|
74
|
+
flexmock(I18n).should_receive(:t).with("numbers.1").and_return "translation missing"
|
75
|
+
flexmock(I18n).should_receive(:t).with("numbers.2").and_return "translation missing"
|
76
|
+
flexmock(I18n).should_receive(:t).with("numbers.3").and_return "translation missing"
|
77
|
+
flexmock(I18n).should_receive(:t).with("voicemail.messages.message_received_from_x", from: "123").and_return "Message received from 123."
|
78
|
+
should_play "Message received from 123."
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -36,15 +36,33 @@ describe Voicemail::MailboxSetGreetingController do
|
|
36
36
|
let(:recording_component) { flexmock 'Record' }
|
37
37
|
let(:file_path) { "/path/to/file" }
|
38
38
|
|
39
|
-
|
39
|
+
before do
|
40
40
|
should_play config.set_greeting.before_record
|
41
|
-
recording_component.should_receive("complete_event.recording.uri").and_return
|
42
|
-
subject.should_receive(:record).once.with(config.set_greeting.recording.to_hash.merge(interruptible: true)).and_return recording_component
|
41
|
+
recording_component.should_receive("complete_event.recording.uri").and_return file_path
|
43
42
|
subject.should_receive(:play_audio).with file_path
|
44
|
-
subject.should_receive(:menu).once.with
|
45
|
-
|
46
|
-
|
43
|
+
subject.should_receive(:menu).once.with config.set_greeting.after_record, {timeout: config.menu_timeout, tries: config.menu_tries}, Proc
|
44
|
+
end
|
45
|
+
|
46
|
+
after do
|
47
47
|
controller.record_greeting
|
48
|
+
config.use_mailbox_opts_for_recording = false
|
49
|
+
end
|
50
|
+
|
51
|
+
context "without mailbox settings" do
|
52
|
+
it "plays the appropriate sounds, records, plays back recording, and calls the recording menu" do
|
53
|
+
subject.should_receive(:record).once.with(config.recording.to_hash).and_return recording_component
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "with mailbox settings" do
|
58
|
+
let(:mailbox) { {id: 100, record_options: {final_timeout: 31}} }
|
59
|
+
|
60
|
+
before { config.use_mailbox_opts_for_recording = true }
|
61
|
+
|
62
|
+
it "records using the mailbox's record options" do
|
63
|
+
expected_options = {direction: :send, final_timeout: 31, interruptible: true, max_duration: 30, start_beep: true, stop_beep: false}
|
64
|
+
subject.should_receive(:record).once.with(expected_options).and_return recording_component
|
65
|
+
end
|
48
66
|
end
|
49
67
|
end
|
50
68
|
|
File without changes
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Voicemail::VoicemailController do
|
4
|
+
include VoicemailControllerSpecHelper
|
5
|
+
|
6
|
+
describe "#run" do
|
7
|
+
context "with a missing mailbox parameter in metadata" do
|
8
|
+
let(:metadata) { Hash.new }
|
9
|
+
|
10
|
+
it "should raise an error if there is no mailbox in the metadata" do
|
11
|
+
subject.should_receive(:answer).once
|
12
|
+
expect { controller.run }.to raise_error ArgumentError
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "When when_to_answer is :after_greeting and there's no mailbox" do
|
17
|
+
let(:mailbox) { nil }
|
18
|
+
|
19
|
+
before { config.when_to_answer = :after_greeting }
|
20
|
+
after { config.when_to_answer = :before_greeting }
|
21
|
+
|
22
|
+
it "should not answer" do
|
23
|
+
should_play config.mailbox_not_found
|
24
|
+
subject.should_receive(:hangup).once
|
25
|
+
controller.run
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "with a present mailbox parameter in metadata" do
|
30
|
+
before { subject.should_receive(:answer).once }
|
31
|
+
|
32
|
+
context "with an invalid mailbox" do
|
33
|
+
let(:mailbox) { nil }
|
34
|
+
|
35
|
+
it "plays the mailbox not found message and hangs up" do
|
36
|
+
should_play config.mailbox_not_found
|
37
|
+
subject.should_receive(:hangup).once
|
38
|
+
controller.run
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "with an existing mailbox" do
|
43
|
+
before { subject.should_receive(:hangup).once }
|
44
|
+
|
45
|
+
context "without a greeting message" do
|
46
|
+
it "plays the default greeting if one is not specified" do
|
47
|
+
should_play config.default_greeting
|
48
|
+
subject.should_receive :record_message
|
49
|
+
controller.run
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "with a specified greeting message" do
|
54
|
+
let(:greeting_message) { "Howdy!" }
|
55
|
+
|
56
|
+
it "plays the specific greeting message" do
|
57
|
+
should_play greeting_message
|
58
|
+
subject.should_receive :record_message
|
59
|
+
controller.run
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#record_message" do
|
67
|
+
context "handling a recording" do
|
68
|
+
let(:recording_component) { flexmock 'Record' }
|
69
|
+
let(:recording_object) { flexmock 'complete_event.recording', uri: "http://some_file.wav" }
|
70
|
+
|
71
|
+
after { subject.record_message }
|
72
|
+
|
73
|
+
context "without allow_rerecording" do
|
74
|
+
before { config.allow_rerecording = false }
|
75
|
+
|
76
|
+
it "saves the recording" do
|
77
|
+
recording_component.should_receive("complete_event.recording").and_return recording_object
|
78
|
+
subject.should_receive(:record).with(config.recording.to_hash).and_return recording_component
|
79
|
+
storage_instance.should_receive(:save_recording).with mailbox[:id], call.from, recording_object
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "without allow_rerecording" do
|
84
|
+
before { config.allow_rerecording = true }
|
85
|
+
|
86
|
+
it "sets up a callback, plays a menu, and eventually saves the message" do
|
87
|
+
call.should_receive :on_end
|
88
|
+
recording_object.should_receive :uri
|
89
|
+
subject.should_receive(:menu)
|
90
|
+
recording_component.should_receive("complete_event.recording").and_return recording_object
|
91
|
+
subject.should_receive(:record).with(config.recording.to_hash).and_return recording_component
|
92
|
+
storage_instance.should_receive(:save_recording).with mailbox[:id], call.from, recording_object
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|