telephony 1.0.3

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 (365) hide show
  1. checksums.yaml +15 -0
  2. data/README.md +105 -0
  3. data/Rakefile +39 -0
  4. data/app/assets/fonts/telephony/zest-telephony.eot +0 -0
  5. data/app/assets/fonts/telephony/zest-telephony.svg +73 -0
  6. data/app/assets/fonts/telephony/zest-telephony.ttf +0 -0
  7. data/app/assets/fonts/telephony/zest-telephony.woff +0 -0
  8. data/app/assets/images/telephony/backspace.png +0 -0
  9. data/app/assets/images/telephony/icon-spinner.gif +0 -0
  10. data/app/assets/javascripts/telephony/application.js +12 -0
  11. data/app/assets/javascripts/telephony/collections/agents.js +4 -0
  12. data/app/assets/javascripts/telephony/config.js.erb +11 -0
  13. data/app/assets/javascripts/telephony/models/agent.js +103 -0
  14. data/app/assets/javascripts/telephony/models/conversation.js +226 -0
  15. data/app/assets/javascripts/telephony/models/device.js +30 -0
  16. data/app/assets/javascripts/telephony/models/transfer.js +65 -0
  17. data/app/assets/javascripts/telephony/namespace.js +6 -0
  18. data/app/assets/javascripts/telephony/push.js +80 -0
  19. data/app/assets/javascripts/telephony/vendor/backbone.js +1159 -0
  20. data/app/assets/javascripts/telephony/vendor/chosen.jquery.js +1018 -0
  21. data/app/assets/javascripts/telephony/vendor/jquery.form.js +1117 -0
  22. data/app/assets/javascripts/telephony/vendor/pusher.js +1304 -0
  23. data/app/assets/javascripts/telephony/vendor/test_dependencies.js +18 -0
  24. data/app/assets/javascripts/telephony/vendor/underscore.js +839 -0
  25. data/app/assets/javascripts/telephony/views/agents_view.js +69 -0
  26. data/app/assets/javascripts/telephony/views/application_view.js +78 -0
  27. data/app/assets/javascripts/telephony/views/call_queue_view.js +21 -0
  28. data/app/assets/javascripts/telephony/views/conversation_buttons_view.js +15 -0
  29. data/app/assets/javascripts/telephony/views/conversation_view.js +322 -0
  30. data/app/assets/javascripts/telephony/views/status_view.js +36 -0
  31. data/app/assets/javascripts/telephony/views/transfer_view.js +87 -0
  32. data/app/assets/javascripts/telephony/views/twilio_client_view.js +117 -0
  33. data/app/assets/javascripts/telephony/views/widget_view.js +55 -0
  34. data/app/assets/javascripts/telephony/widget.js +5 -0
  35. data/app/assets/javascripts/templates/telephony/agents_view.jst.ejs +8 -0
  36. data/app/assets/javascripts/templates/telephony/call_queue_view.jst.ejs +2 -0
  37. data/app/assets/javascripts/templates/telephony/conversation_buttons_view.jst.ejs +23 -0
  38. data/app/assets/javascripts/templates/telephony/conversation_view.jst.ejs +10 -0
  39. data/app/assets/javascripts/templates/telephony/status_view.jst.ejs +4 -0
  40. data/app/assets/javascripts/templates/telephony/transfer_view.jst.ejs +38 -0
  41. data/app/assets/javascripts/templates/telephony/twilio_client_view.jst.ejs +10 -0
  42. data/app/assets/stylesheets/telephony/font.css +43 -0
  43. data/app/assets/stylesheets/telephony/reset.css.scss +10 -0
  44. data/app/assets/stylesheets/telephony/widget.css.scss +512 -0
  45. data/app/controllers/telephony/agents_controller.rb +46 -0
  46. data/app/controllers/telephony/application_controller.rb +4 -0
  47. data/app/controllers/telephony/call_centers_controller.rb +9 -0
  48. data/app/controllers/telephony/conversations_controller.rb +74 -0
  49. data/app/controllers/telephony/inbound/conversation_queues_controller.rb +21 -0
  50. data/app/controllers/telephony/playable_listeners_controller.rb +43 -0
  51. data/app/controllers/telephony/providers/twilio/application_controller.rb +26 -0
  52. data/app/controllers/telephony/providers/twilio/calls_controller.rb +130 -0
  53. data/app/controllers/telephony/providers/twilio/inbound_calls_controller.rb +54 -0
  54. data/app/controllers/telephony/providers/twilio/musics_controller.rb +12 -0
  55. data/app/controllers/telephony/providers/twilio/voicemails_controller.rb +29 -0
  56. data/app/controllers/telephony/signals/agents/presences_controller.rb +64 -0
  57. data/app/controllers/telephony/transfers_controller.rb +18 -0
  58. data/app/controllers/telephony/twilio_client_controller.rb +37 -0
  59. data/app/controllers/telephony/voicemails_controller.rb +13 -0
  60. data/app/controllers/telephony/widget_controller.rb +10 -0
  61. data/app/helpers/telephony/application_helper.rb +4 -0
  62. data/app/helpers/telephony/calls_helper.rb +13 -0
  63. data/app/models/telephony/agent.rb +186 -0
  64. data/app/models/telephony/agent_state_machine.rb +54 -0
  65. data/app/models/telephony/base.rb +7 -0
  66. data/app/models/telephony/blacklisted_number.rb +5 -0
  67. data/app/models/telephony/call.rb +94 -0
  68. data/app/models/telephony/call_center.rb +26 -0
  69. data/app/models/telephony/call_state_machine.rb +98 -0
  70. data/app/models/telephony/conversation.rb +273 -0
  71. data/app/models/telephony/conversation_state_machine.rb +109 -0
  72. data/app/models/telephony/conversations_presenter.rb +83 -0
  73. data/app/models/telephony/events.rb +6 -0
  74. data/app/models/telephony/events/answer.rb +6 -0
  75. data/app/models/telephony/events/base.rb +118 -0
  76. data/app/models/telephony/events/busy.rb +6 -0
  77. data/app/models/telephony/events/call_answered.rb +22 -0
  78. data/app/models/telephony/events/call_fail.rb +6 -0
  79. data/app/models/telephony/events/complete_hold.rb +28 -0
  80. data/app/models/telephony/events/complete_one_step_transfer.rb +17 -0
  81. data/app/models/telephony/events/complete_resume.rb +28 -0
  82. data/app/models/telephony/events/complete_two_step_transfer.rb +6 -0
  83. data/app/models/telephony/events/conference.rb +6 -0
  84. data/app/models/telephony/events/connect.rb +22 -0
  85. data/app/models/telephony/events/customer_left_two_step_transfer.rb +6 -0
  86. data/app/models/telephony/events/dial_agent.rb +6 -0
  87. data/app/models/telephony/events/ended.rb +19 -0
  88. data/app/models/telephony/events/enqueue.rb +6 -0
  89. data/app/models/telephony/events/fail_one_step_transfer.rb +9 -0
  90. data/app/models/telephony/events/fail_two_step_transfer.rb +6 -0
  91. data/app/models/telephony/events/initialize_widget.rb +15 -0
  92. data/app/models/telephony/events/initiate_hold.rb +6 -0
  93. data/app/models/telephony/events/initiate_one_step_transfer.rb +6 -0
  94. data/app/models/telephony/events/initiate_resume.rb +6 -0
  95. data/app/models/telephony/events/initiate_two_step_transfer.rb +6 -0
  96. data/app/models/telephony/events/leave_two_step_transfer.rb +17 -0
  97. data/app/models/telephony/events/leave_voicemail.rb +22 -0
  98. data/app/models/telephony/events/no_answer.rb +6 -0
  99. data/app/models/telephony/events/play_closed_greeting.rb +6 -0
  100. data/app/models/telephony/events/play_message.rb +6 -0
  101. data/app/models/telephony/events/reject.rb +6 -0
  102. data/app/models/telephony/events/rona.rb +6 -0
  103. data/app/models/telephony/events/start.rb +17 -0
  104. data/app/models/telephony/events/straight_to_voicemail.rb +6 -0
  105. data/app/models/telephony/events/terminate.rb +6 -0
  106. data/app/models/telephony/events/transfer.rb +35 -0
  107. data/app/models/telephony/inbound_conversation_queue.rb +101 -0
  108. data/app/models/telephony/playable.rb +7 -0
  109. data/app/models/telephony/playable_listener.rb +42 -0
  110. data/app/models/telephony/pusher_event_publisher.rb +26 -0
  111. data/app/models/telephony/recording.rb +4 -0
  112. data/app/models/telephony/voicemail.rb +36 -0
  113. data/app/observers/telephony/agent_observer.rb +8 -0
  114. data/app/observers/telephony/call_observer.rb +15 -0
  115. data/app/observers/telephony/conversation_observer.rb +9 -0
  116. data/app/observers/telephony/event_observer.rb +9 -0
  117. data/app/views/layouts/telephony/application.html.erb +14 -0
  118. data/app/views/telephony/providers/twilio/calls/child_detached.builder +5 -0
  119. data/app/views/telephony/providers/twilio/calls/complete_hold.builder +6 -0
  120. data/app/views/telephony/providers/twilio/calls/connect.builder +13 -0
  121. data/app/views/telephony/providers/twilio/calls/dial.builder +14 -0
  122. data/app/views/telephony/providers/twilio/calls/done.builder +5 -0
  123. data/app/views/telephony/providers/twilio/calls/join_conference.builder +7 -0
  124. data/app/views/telephony/providers/twilio/calls/whisper_tone.builder +3 -0
  125. data/app/views/telephony/providers/twilio/inbound_calls/closed_hours.builder +7 -0
  126. data/app/views/telephony/providers/twilio/inbound_calls/create.builder +8 -0
  127. data/app/views/telephony/providers/twilio/inbound_calls/enqueue.builder +8 -0
  128. data/app/views/telephony/providers/twilio/inbound_calls/reject.builder +5 -0
  129. data/app/views/telephony/providers/twilio/inbound_calls/wait_music.builder +5 -0
  130. data/app/views/telephony/providers/twilio/musics/hold.builder +5 -0
  131. data/app/views/telephony/providers/twilio/voicemails/new.builder +6 -0
  132. data/app/views/telephony/twilio_client/index.html.erb +74 -0
  133. data/app/views/telephony/widget/index.erb +3 -0
  134. data/config/cucumber.yml +8 -0
  135. data/config/database.yml +57 -0
  136. data/config/environment.rb +67 -0
  137. data/config/initializers/pusher.rb +21 -0
  138. data/config/initializers/telephony.rb +44 -0
  139. data/config/routes.rb +94 -0
  140. data/config/wopr.yml.example +38 -0
  141. data/db/migrate/20130806213053_bootstrap_db.rb +105 -0
  142. data/db/migrate/20131009204026_create_telephony_blacklisted_numbers.rb +11 -0
  143. data/lib/agent_generator.rb +24 -0
  144. data/lib/tasks/cucumber.rake +65 -0
  145. data/lib/tasks/jasmine.rake +8 -0
  146. data/lib/tasks/telephony_tasks.rake +4 -0
  147. data/lib/telephony.rb +34 -0
  148. data/lib/telephony/concerns/controllers/twilio_request_verifier.rb +39 -0
  149. data/lib/telephony/conversation_data.rb +67 -0
  150. data/lib/telephony/engine.rb +19 -0
  151. data/lib/telephony/error.rb +8 -0
  152. data/lib/telephony/error/agent_on_a_call.rb +2 -0
  153. data/lib/telephony/error/base.rb +3 -0
  154. data/lib/telephony/error/connection.rb +2 -0
  155. data/lib/telephony/error/not_in_progress.rb +2 -0
  156. data/lib/telephony/error/queue_empty.rb +2 -0
  157. data/lib/telephony/helper.rb +11 -0
  158. data/lib/telephony/jobs/agent_offline.rb +28 -0
  159. data/lib/telephony/jobs/pusher_event.rb +21 -0
  160. data/lib/telephony/providers/twilio_provider.rb +162 -0
  161. data/lib/telephony/version.rb +3 -0
  162. data/spec/controllers/telephony/agents_controller_spec.rb +117 -0
  163. data/spec/controllers/telephony/call_centers_controller_spec.rb +25 -0
  164. data/spec/controllers/telephony/conversations_controller_spec.rb +229 -0
  165. data/spec/controllers/telephony/playable_listeners_controller_spec.rb +138 -0
  166. data/spec/controllers/telephony/providers/twilio/calls_controller_spec.rb +33 -0
  167. data/spec/controllers/telephony/providers/twilio/musics_controller_spec.rb +20 -0
  168. data/spec/controllers/telephony/signals/agents/presences_controller_spec.rb +154 -0
  169. data/spec/controllers/telephony/twilio_client_controller_spec.rb +58 -0
  170. data/spec/controllers/telephony/widget_controller_spec.rb +25 -0
  171. data/spec/dummy/Rakefile +7 -0
  172. data/spec/dummy/app/assets/javascripts/application.js +6 -0
  173. data/spec/dummy/app/assets/javascripts/lib/event_logger.js +82 -0
  174. data/spec/dummy/app/assets/javascripts/vendor/backbone.js +1159 -0
  175. data/spec/dummy/app/assets/javascripts/vendor/chosen.jquery.js +1018 -0
  176. data/spec/dummy/app/assets/javascripts/vendor/jquery.form.js +1117 -0
  177. data/spec/dummy/app/assets/javascripts/vendor/underscore.js +839 -0
  178. data/spec/dummy/app/assets/stylesheets/application.css +23 -0
  179. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  180. data/spec/dummy/app/controllers/widget_host_controller.rb +2 -0
  181. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  182. data/spec/dummy/app/views/layouts/application.html.erb +12 -0
  183. data/spec/dummy/app/views/widget_host/index.html.erb +53 -0
  184. data/spec/dummy/config.ru +4 -0
  185. data/spec/dummy/config/application.rb +61 -0
  186. data/spec/dummy/config/boot.rb +10 -0
  187. data/spec/dummy/config/call_centers.yml +35 -0
  188. data/spec/dummy/config/call_centers.yml.example +35 -0
  189. data/spec/dummy/config/database.yml +56 -0
  190. data/spec/dummy/config/environment.rb +5 -0
  191. data/spec/dummy/config/environments/cucumber.rb +39 -0
  192. data/spec/dummy/config/environments/development.rb +39 -0
  193. data/spec/dummy/config/environments/production.rb +67 -0
  194. data/spec/dummy/config/environments/test.rb +39 -0
  195. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  196. data/spec/dummy/config/initializers/inflections.rb +15 -0
  197. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  198. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  199. data/spec/dummy/config/initializers/session_store.rb +8 -0
  200. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  201. data/spec/dummy/config/locales/en.yml +5 -0
  202. data/spec/dummy/config/pusher.yml +14 -0
  203. data/spec/dummy/config/pusher.yml.example +14 -0
  204. data/spec/dummy/config/routes.rb +5 -0
  205. data/spec/dummy/config/sms_whitelist.json.example +4 -0
  206. data/spec/dummy/config/twilio.yml +57 -0
  207. data/spec/dummy/config/twilio.yml.example +57 -0
  208. data/spec/dummy/db/schema.rb +122 -0
  209. data/spec/dummy/db/seeds.rb +6 -0
  210. data/spec/dummy/log/production.log +156 -0
  211. data/spec/dummy/log/test.log +13812 -0
  212. data/spec/dummy/public/404.html +26 -0
  213. data/spec/dummy/public/422.html +26 -0
  214. data/spec/dummy/public/500.html +25 -0
  215. data/spec/dummy/public/assets/application-628309db7ce8c0abdd91f8f796881599.js +32 -0
  216. data/spec/dummy/public/assets/application-628309db7ce8c0abdd91f8f796881599.js.gz +0 -0
  217. data/spec/dummy/public/assets/application-6c551430f3bdd32ba57c9c41e5f91846.css +24 -0
  218. data/spec/dummy/public/assets/application-6c551430f3bdd32ba57c9c41e5f91846.css.gz +0 -0
  219. data/spec/dummy/public/assets/telephony/backspace-9f5b195e049ed90eb20ecdda6e264b0a.png +0 -0
  220. data/spec/dummy/public/assets/telephony/icon-spinner-ddbae473a70c5425810aeee31d4a8ad7.gif +0 -0
  221. data/spec/dummy/public/assets/telephony/zest-telephony-0e6b13673634da80de9ae09bcca253e3.eot +0 -0
  222. data/spec/dummy/public/assets/telephony/zest-telephony-37f394757ccb11b978f16d9fd32cb3b5.ttf +0 -0
  223. data/spec/dummy/public/assets/telephony/zest-telephony-e7efdbc60c0a1c8404951bc79c7fb3a8.woff +0 -0
  224. data/spec/dummy/public/assets/telephony/zest-telephony-f34287df626936908408f53a33db9e83.svg +73 -0
  225. data/spec/dummy/public/favicon.ico +0 -0
  226. data/spec/dummy/script/rails +6 -0
  227. data/spec/dummy/tmp/cache/assets/C98/020/sprockets%2Fa83f8254d688334ff179984e423f502f +0 -0
  228. data/spec/dummy/tmp/cache/assets/CA4/550/sprockets%2F407f9191fe573f2435c55c017cb0d022 +0 -0
  229. data/spec/dummy/tmp/cache/assets/CAA/6A0/sprockets%2F3265550e2d2c7f5a864ca85d255504c2 +0 -0
  230. data/spec/dummy/tmp/cache/assets/CB0/F60/sprockets%2F462f9efed31e6710732376ae06c27208 +0 -0
  231. data/spec/dummy/tmp/cache/assets/CB6/E20/sprockets%2Fa7092cd9f16917099d754f1380af13e1 +0 -0
  232. data/spec/dummy/tmp/cache/assets/CC7/9F0/sprockets%2F0517100815cd45c43fec1d8510fcb630 +0 -0
  233. data/spec/dummy/tmp/cache/assets/CCA/BF0/sprockets%2F16ea15e0b5d367c34b812612a4207e3e +0 -0
  234. data/spec/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
  235. data/spec/dummy/tmp/cache/assets/CF1/960/sprockets%2F36ef26985821ec702c74dae4af789903 +0 -0
  236. data/spec/dummy/tmp/cache/assets/D07/F30/sprockets%2Fd12862f20df0c9ef7aa2b4216d247079 +0 -0
  237. data/spec/dummy/tmp/cache/assets/D09/BF0/sprockets%2F5c8595efaa8cc5235a09801c60e25a16 +0 -0
  238. data/spec/dummy/tmp/cache/assets/D0D/250/sprockets%2F5e759d66e374910dae5a51b221e6e3a4 +0 -0
  239. data/spec/dummy/tmp/cache/assets/D0D/E30/sprockets%2Fa282879e0788ba133f5bdc211cf134e8 +0 -0
  240. data/spec/dummy/tmp/cache/assets/D11/8E0/sprockets%2F2a193a8af29963f1113bef05788e02ff +0 -0
  241. data/spec/dummy/tmp/cache/assets/D14/270/sprockets%2F7f95a752910ed33d728532f8fabd340d +0 -0
  242. data/spec/dummy/tmp/cache/assets/D17/BE0/sprockets%2F58749d7aea4ca766c2520801f0f96b9b +0 -0
  243. data/spec/dummy/tmp/cache/assets/D18/270/sprockets%2Fbb2d88813b1795a97e9a7c14100eef77 +0 -0
  244. data/spec/dummy/tmp/cache/assets/D22/310/sprockets%2Fbae9148ce1229214dfbb0c425b0054d0 +0 -0
  245. data/spec/dummy/tmp/cache/assets/D30/EB0/sprockets%2F2c668b88beb4c9805d91ed4587f549e7 +0 -0
  246. data/spec/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  247. data/spec/dummy/tmp/cache/assets/D3C/690/sprockets%2F681ba175fdd2da8d590b7e624b6135a6 +0 -0
  248. data/spec/dummy/tmp/cache/assets/D44/BC0/sprockets%2F7214f66dd91fdd51f00c3882293f5eea +0 -0
  249. data/spec/dummy/tmp/cache/assets/D46/FA0/sprockets%2F4f9543cd9e68ba3141fd488afb13681b +0 -0
  250. data/spec/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
  251. data/spec/dummy/tmp/cache/assets/D51/9A0/sprockets%2Fb6e4cbcf30f6f611671695f79ea846d5 +0 -0
  252. data/spec/dummy/tmp/cache/assets/D55/920/sprockets%2F0a02242aa4c4febcc796419aba103c69 +0 -0
  253. data/spec/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
  254. data/spec/dummy/tmp/cache/assets/D5F/6F0/sprockets%2F155e7bc44f326371cce0ca8bc5b2414e +0 -0
  255. data/spec/dummy/tmp/cache/assets/D6B/250/sprockets%2Fe4eecce7a3371b11038c92f07cb28e67 +0 -0
  256. data/spec/dummy/tmp/cache/assets/D6B/E70/sprockets%2F103a456ae3692e3cca20b7696fdee8f0 +0 -0
  257. data/spec/dummy/tmp/cache/assets/D7F/AD0/sprockets%2Fb1c02d12303b1fe2f981771cbb0c4cbd +0 -0
  258. data/spec/dummy/tmp/cache/assets/D81/D00/sprockets%2F0c68b6d9dce98681a2a710d9fc3f7e39 +0 -0
  259. data/spec/dummy/tmp/cache/assets/D94/4D0/sprockets%2F4608a5bdf27ddf11bcaed1375911e9a2 +0 -0
  260. data/spec/dummy/tmp/cache/assets/D9A/580/sprockets%2F433005b19aaf7ed5cba9c7f8cd30b775 +0 -0
  261. data/spec/dummy/tmp/cache/assets/DA4/270/sprockets%2F860ab3bd30204e02c0a5d82bd4bbabe1 +0 -0
  262. data/spec/dummy/tmp/cache/assets/DA4/480/sprockets%2F53e39285bb57a2ddb6ff856b2eb491da +0 -0
  263. data/spec/dummy/tmp/cache/assets/DA6/3C0/sprockets%2F587c7e35f47442eadaa530acc5e9f5e6 +0 -0
  264. data/spec/dummy/tmp/cache/assets/DAB/DA0/sprockets%2Fb8fb5e8518ed3d38a7f6a8f18a9208aa +0 -0
  265. data/spec/dummy/tmp/cache/assets/DB2/700/sprockets%2Ffa85cb79b94fce1b8344d983ea863d2e +0 -0
  266. data/spec/dummy/tmp/cache/assets/DCC/4F0/sprockets%2Fbc0f3c61e16afb5a285ba8b39846ed8b +0 -0
  267. data/spec/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
  268. data/spec/dummy/tmp/cache/assets/DDC/BE0/sprockets%2F2c0a4d4675a61b014aedbbabb3f071fc +0 -0
  269. data/spec/dummy/tmp/cache/assets/E04/640/sprockets%2F3c5ddf2bbefd9d70f1b506b519cf856e +0 -0
  270. data/spec/dummy/tmp/cache/assets/E04/7F0/sprockets%2F35f1b2ff729a5ec21f6dc5f7d6faa67b +0 -0
  271. data/spec/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  272. data/spec/dummy/tmp/cache/assets/E07/230/sprockets%2Febd4f2dd708879d593aff008ccb75acc +0 -0
  273. data/spec/dummy/tmp/cache/assets/E17/9D0/sprockets%2F8db2b79f6c4eabe7a9ebe7a7898ec066 +0 -0
  274. data/spec/dummy/tmp/cache/assets/E31/F10/sprockets%2Fcebacf56667da1cc2961b59fd922eafb +0 -0
  275. data/spec/factories/agent.rb +26 -0
  276. data/spec/factories/calls.rb +106 -0
  277. data/spec/factories/conversations.rb +171 -0
  278. data/spec/factories/events.rb +250 -0
  279. data/spec/factories/playable_listeners.rb +6 -0
  280. data/spec/factories/recordings.rb +6 -0
  281. data/spec/factories/voicemails.rb +8 -0
  282. data/spec/fixtures/vcr_cassettes/Authenticating_an_online_user.yml +90 -0
  283. data/spec/fixtures/vcr_cassettes/Creating_a_conversation/creates_a_new_call.yml +42 -0
  284. data/spec/fixtures/vcr_cassettes/Creating_a_conversation/creates_a_new_conversation.yml +42 -0
  285. data/spec/fixtures/vcr_cassettes/Creating_a_conversation/returns_the_conversation_as_JSON.yml +42 -0
  286. data/spec/fixtures/vcr_cassettes/Pusher_channel_as_JSON.yml +90 -0
  287. data/spec/fixtures/vcr_cassettes/Pusher_to_publish_the_event.yml +32 -0
  288. data/spec/fixtures/vcr_cassettes/Reloading_the_widget_during_a_call/_create/during_a_call/after_a_failed_transfer/pushes_the_event_for_the_active_call.yml +1110 -0
  289. data/spec/fixtures/vcr_cassettes/Telephony_ConversationsController/_create/by_default/creates_a_new_call.yml +45 -0
  290. data/spec/fixtures/vcr_cassettes/Telephony_ConversationsController/_create/by_default/creates_a_new_conversation.yml +43 -0
  291. data/spec/fixtures/vcr_cassettes/Telephony_ConversationsController/_create/by_default/returns_the_conversation_as_JSON.yml +44 -0
  292. data/spec/fixtures/vcr_cassettes/Telephony_Providers_TwilioProvider/_call/allows_the_phone_to_ring_for_60_seconds.yml +42 -0
  293. data/spec/fixtures/vcr_cassettes/Telephony_Providers_TwilioProvider/_call/includes_a_status_change_callback_url.yml +42 -0
  294. data/spec/fixtures/vcr_cassettes/Telephony_Providers_TwilioProvider/_call/places_a_call.yml +42 -0
  295. data/spec/fixtures/vcr_cassettes/Telephony_Providers_TwilioProvider/_dial_into_conference/allows_the_phone_to_ring_for_15_seconds.yml +42 -0
  296. data/spec/fixtures/vcr_cassettes/Telephony_Providers_TwilioProvider/_dial_into_conference/places_a_call_to_redirect_the_participant_to_a_conference.yml +42 -0
  297. data/spec/fixtures/vcr_cassettes/Telephony_Providers_TwilioProvider/_hangup/by_default/hangs_up_the_call.yml +42 -0
  298. data/spec/fixtures/vcr_cassettes/buying_number_for_an_area_code.yml +42 -0
  299. data/spec/fixtures/vcr_cassettes/returns_success.yml +90 -0
  300. data/spec/javascripts/helpers/jasmine-jquery.js +546 -0
  301. data/spec/javascripts/helpers/mock-ajax.js +207 -0
  302. data/spec/javascripts/support/jasmine.yml +80 -0
  303. data/spec/javascripts/telephony/models/agent_spec.js +40 -0
  304. data/spec/javascripts/telephony/models/conversation_spec.js +515 -0
  305. data/spec/javascripts/telephony/models/device_spec.js +80 -0
  306. data/spec/javascripts/telephony/models/transfer_spec.js +22 -0
  307. data/spec/javascripts/telephony/push_spec.js +427 -0
  308. data/spec/javascripts/telephony/views/agents_view_spec.js +101 -0
  309. data/spec/javascripts/telephony/views/application_view_spec.js +74 -0
  310. data/spec/javascripts/telephony/views/conversation_view_spec.js +626 -0
  311. data/spec/javascripts/telephony/views/status_view_spec.js +30 -0
  312. data/spec/javascripts/telephony/views/transfer_view_spec.js +187 -0
  313. data/spec/javascripts/telephony/views/twilio_client_view_spec.js +77 -0
  314. data/spec/javascripts/telephony/views/widget_view_spec.js +20 -0
  315. data/spec/lib/telephony/concerns/controllers/twilio_request_verifier_spec.rb +77 -0
  316. data/spec/lib/telephony/conversation_data_spec.rb +342 -0
  317. data/spec/lib/telephony/helper_spec.rb +24 -0
  318. data/spec/lib/telephony/jobs/agent_offline_spec.rb +37 -0
  319. data/spec/lib/telephony/jobs/pusher_event_spec.rb +39 -0
  320. data/spec/lib/telephony/providers/twilio_provider_spec.rb +439 -0
  321. data/spec/lib/telephony_spec.rb +104 -0
  322. data/spec/models/telephony/agent_spec.rb +479 -0
  323. data/spec/models/telephony/agent_state_machine_spec.rb +131 -0
  324. data/spec/models/telephony/call_center_spec.rb +32 -0
  325. data/spec/models/telephony/call_spec.rb +597 -0
  326. data/spec/models/telephony/call_state_machine_spec.rb +472 -0
  327. data/spec/models/telephony/conversation_spec.rb +751 -0
  328. data/spec/models/telephony/conversation_state_machine_spec.rb +387 -0
  329. data/spec/models/telephony/conversations_presenter_spec.rb +40 -0
  330. data/spec/models/telephony/event_spec.rb +716 -0
  331. data/spec/models/telephony/inbound_conversation_queue_spec.rb +243 -0
  332. data/spec/models/telephony/playable_listener_spec.rb +43 -0
  333. data/spec/models/telephony/pusher_event_publisher_spec.rb +36 -0
  334. data/spec/models/telephony/recording_spec.rb +6 -0
  335. data/spec/models/telephony/voicemail_spec.rb +96 -0
  336. data/spec/observers/telephony/agent_observer_spec.rb +21 -0
  337. data/spec/observers/telephony/event_observer_spec.rb +19 -0
  338. data/spec/requests/create_conversation_spec.rb +39 -0
  339. data/spec/requests/dequeue_call_spec.rb +42 -0
  340. data/spec/requests/list_conversations_spec.rb +33 -0
  341. data/spec/requests/presences_spec.rb +51 -0
  342. data/spec/requests/providers/twilio/calls/child_answered_spec.rb +24 -0
  343. data/spec/requests/providers/twilio/calls/child_detached_spec.rb +249 -0
  344. data/spec/requests/providers/twilio/calls/dial_spec.rb +132 -0
  345. data/spec/requests/providers/twilio/calls/done_spec.rb +69 -0
  346. data/spec/requests/providers/twilio/calls/join_conference_spec.rb +56 -0
  347. data/spec/requests/providers/twilio/calls/leave_queue_spec.rb +44 -0
  348. data/spec/requests/providers/twilio/calls/parent_answered_spec.rb +59 -0
  349. data/spec/requests/providers/twilio/inbound/connect_dequeued_call_spec.rb +124 -0
  350. data/spec/requests/providers/twilio/inbound/enqueue_inbound_call_spec.rb +108 -0
  351. data/spec/requests/providers/twilio/inbound/enqueued_call_wait_music_spec.rb +13 -0
  352. data/spec/requests/providers/twilio/voicemails/leave_voicemail_spec.rb +78 -0
  353. data/spec/requests/search_conversations_spec.rb +101 -0
  354. data/spec/requests/transfer_spec.rb +65 -0
  355. data/spec/requests/voicemail_api_spec.rb +58 -0
  356. data/spec/spec_helper.rb +27 -0
  357. data/spec/support/factory_girl.rb +5 -0
  358. data/spec/support/matchers/be_complete_hold.rb +20 -0
  359. data/spec/support/matchers/be_whisper_tone.rb +35 -0
  360. data/spec/support/matchers/join_conference.rb +23 -0
  361. data/spec/support/nokogiri.rb +1 -0
  362. data/spec/support/pusher_helper.rb +24 -0
  363. data/spec/support/vcr.rb +12 -0
  364. data/spec/support/webmock.rb +1 -0
  365. metadata +692 -0
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ module Telephony
4
+ describe EventObserver do
5
+ before do
6
+ ActiveRecord::Base.observers.enable 'Telephony::EventObserver'
7
+ EventObserver.instance
8
+ end
9
+
10
+ describe "#after_create" do
11
+ let(:event) { build(:event) }
12
+
13
+ it "asks its event to publish itself" do
14
+ event.should_receive(:publish)
15
+ event.save!
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Creating a conversation', :vcr do
4
+ before do
5
+ agent = create :agent, csr_type: 'B'
6
+ attributes = {
7
+ from: '310-456-7890',
8
+ to: '310-765-4321',
9
+ loan_id: 1,
10
+ from_id: agent.csr_id,
11
+ from_type: 'csr'
12
+ }
13
+ @existing_whitelist = Telephony.whitelist
14
+ Telephony.whitelist = [attributes[:from], attributes[:to]]
15
+ @conversation_count = Telephony::Conversation.count
16
+
17
+ xhr :post,
18
+ '/zestphone/conversations',
19
+ attributes
20
+ end
21
+
22
+ after do
23
+ Telephony.whitelist = @existing_whitelist
24
+ end
25
+
26
+ it 'creates a new conversation' do
27
+ Telephony::Conversation.count.should == @conversation_count + 1
28
+ end
29
+
30
+ it 'creates a new call' do
31
+ Telephony::Call.count.should == 2
32
+ end
33
+
34
+ it 'returns the conversation as JSON' do
35
+ conversation = Telephony::Conversation.last
36
+ json = JSON response.body
37
+ json['id'].should == conversation.id
38
+ end
39
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Dequeue an inbound call' do
4
+ context "given there's an inbound call on hold" do
5
+ before do
6
+ conversation = create :conversation
7
+ create :call, conversation: conversation
8
+ create :available_agent, csr_id: 1
9
+ Telephony::Call.any_instance.should_receive(:redirect_to_inbound_connect)
10
+ Telephony::InboundConversationQueue.stub(:oldest_queued_conversation).and_return(conversation)
11
+
12
+ fake_finder = 'fake_finder'
13
+ Telephony.stub(:pop_url_finder).and_return(fake_finder)
14
+ fake_finder.stub(:find).and_return('some_url')
15
+
16
+ delete "/zestphone/inbound/front?csr_id=1"
17
+ end
18
+
19
+ it 'returns the dequeued call as JSON' do
20
+ json = JSON response.body
21
+ json['pop_url'].should == 'some_url'
22
+ end
23
+ end
24
+
25
+ context "given there is NO inbound call on hold" do
26
+ before do
27
+ create :available_agent, csr_id: 1
28
+ delete "/zestphone/inbound/front?csr_id=1"
29
+ end
30
+
31
+ it 'returns 404 Not Found' do
32
+ response.should be_not_found
33
+ end
34
+
35
+ it 'returns an error message' do
36
+ json = JSON response.body
37
+ errors = json['errors']
38
+ errors.should have(1).error
39
+ errors.first.should =~ /queue is empty/i
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'List all conversations' do
4
+ context 'when there are conversations in the system' do
5
+ before do
6
+ create_list :terminated_conversation, 3
7
+ create_list :connecting_conversation, 2
8
+ create_list :in_progress_conversation, 4
9
+ end
10
+
11
+ context 'and given no filtering parameters' do
12
+ before do
13
+ xhr :get, '/zestphone/conversations'
14
+ end
15
+
16
+ it 'returns all conversations and their details' do
17
+ json = JSON response.body
18
+ json.should have(9).items
19
+ end
20
+ end
21
+
22
+ context 'and given filter parameters' do
23
+ before do
24
+ xhr :get, '/zestphone/conversations', state: 'terminated'
25
+ end
26
+
27
+ it 'returns only conversations that match those filters' do
28
+ json = JSON response.body
29
+ json.should have(3).items
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Reloading the widget during a call', :vcr do
4
+ include PusherSignatureHelper
5
+
6
+ describe '#create' do
7
+ context "during a call" do
8
+ context "after a failed transfer" do
9
+ before do
10
+ @conversation1 = create(:connecting_conversation).tap do |conversation|
11
+ create :active_agent_leg, conversation: conversation
12
+ create :connecting_call, conversation: conversation
13
+ end
14
+
15
+ @conversation2 = create(:in_progress_conversation).tap do |conversation|
16
+ create :active_agent_leg, conversation: conversation
17
+ create :customer_leg, conversation: conversation
18
+ end
19
+
20
+ @conversation1.calls.last.answer!
21
+ @conversation1.start!
22
+
23
+ @agent = @conversation1.calls.first.agent
24
+ @agent.available!
25
+ @agent.on_a_call!
26
+
27
+ @payload = {
28
+ "presence" => {
29
+ "time_ms" => 9223372036854775705,
30
+ "events" => [
31
+ { "name" => "member_added",
32
+ "channel" => "presence-#{@agent.csr_id}",
33
+ "user_id" => "#{@agent.id}" }
34
+ ]
35
+ }
36
+ }
37
+ end
38
+
39
+ it "pushes the event for the active call" do
40
+ Telephony::Events::Base.last.should be_a_kind_of(Telephony::Events::Start)
41
+
42
+ @conversation2.transfer!(@conversation1.calls.first.agent.csr_id, true)
43
+
44
+ Telephony::Events::Start.any_instance.should_receive(:republish_only_for)
45
+
46
+ post '/zestphone/signals/agents/presences', @payload.to_query, get_pusher_params(@payload)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'The receiver answering the call' do
4
+ before do
5
+ conversation = create :conversation, state: :connecting
6
+ agent = create :agent
7
+ @call = create :call, sid: nil, state: :connecting,
8
+ conversation: conversation, agent: agent
9
+ @sid = 'sid123'
10
+
11
+ post "/zestphone/providers/twilio/calls/#{@call.id}/child_answered",
12
+ { CallSid: @sid }
13
+
14
+ @call.reload
15
+ end
16
+
17
+ it "updates the call's sid" do
18
+ @call.sid.should == @sid
19
+ end
20
+
21
+ it 'returns an empty TwiML document (whisper tone)' do
22
+ response.body.should be_whisper_tone
23
+ end
24
+ end
@@ -0,0 +1,249 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Given a two step transfer' do
4
+ before do
5
+ @conversation = create :conversation, state: :two_step_transferring
6
+ @call = create :active_agent_leg, conversation: @conversation
7
+ participant = create :call, conversation: @conversation
8
+
9
+ post "/zestphone/providers/twilio/calls/#{@call.id}/child_detached",
10
+ DialCallSid: participant.sid,
11
+ DialCallStatus: 'completed'
12
+ end
13
+
14
+ it 'returns TwiML for redirecting the caller into the same conference' do
15
+ @call.should join_conference
16
+ end
17
+ end
18
+
19
+ describe 'When the child call is completed' do
20
+ context 'and there is a DialCallDuration (which is supposed to mean that the call is hung up)' do
21
+ before do
22
+ agent = create :agent
23
+ @call = create :call, agent: agent
24
+ @conversation = @call.conversation
25
+ @child_call = create :call, conversation: @conversation
26
+ @recording_url = 'recording_url'
27
+ @recording_duration = 0
28
+
29
+ post "/zestphone/providers/twilio/calls/#{@call.id}/child_detached",
30
+ DialCallSid: @child_call.sid,
31
+ DialCallDuration: '0',
32
+ DialCallStatus: 'completed',
33
+ RecordingUrl: @recording_url,
34
+ RecordingDuration: @recording_duration
35
+ end
36
+
37
+ it 'returns TwiML to hangup the caller' do
38
+ response.body.should be_hangup
39
+ end
40
+
41
+ it 'terminates the child call' do
42
+ @child_call.reload
43
+ @child_call.should be_terminated
44
+ end
45
+ end
46
+
47
+ context "and the conversation is initiating_hold" do
48
+ context "and the agent's call is the parent" do
49
+ before do
50
+ agent = create :agent
51
+ @agent_leg = create :holding_agent_call, agent: agent
52
+ @conversation = @agent_leg.conversation
53
+ @cust_leg = create :call, conversation: @conversation
54
+
55
+ post "/zestphone/providers/twilio/calls/#{@agent_leg.id}/child_detached",
56
+ DialCallSid: @cust_leg.sid,
57
+ DialCallStatus: 'completed'
58
+ end
59
+
60
+ it "sets call's state to 'in_conference'" do
61
+ @agent_leg.reload.should be_in_conference
62
+ end
63
+
64
+ it "redirects the call to a conference" do
65
+ @agent_leg.should join_conference
66
+ end
67
+ end
68
+
69
+ context "and the customer's call is the parent" do
70
+ before do
71
+ @cust_leg = create :holding_cust_call
72
+ @conversation = @cust_leg.conversation
73
+ agent = create :agent
74
+ @agent_leg = create :holding_agent_call, agent: agent, conversation: @conversation
75
+
76
+ post "/zestphone/providers/twilio/calls/#{@cust_leg.id}/child_detached",
77
+ DialCallSid: @agent_leg.sid,
78
+ DialCallStatus: 'completed'
79
+ end
80
+
81
+ it "sets call's state to 'in_progress_hold'" do
82
+ @cust_leg.reload.should be_in_progress_hold
83
+ end
84
+
85
+ it "redirects the call to the hold queue" do
86
+ @cust_leg.should complete_hold
87
+ end
88
+ end
89
+ end
90
+
91
+ context 'and there is not a DialCallDuration' do
92
+ before do
93
+ agent = create :agent
94
+ @call = create :call, agent: agent
95
+ @conversation = @call.conversation
96
+ @child_call = create :call, conversation: @conversation
97
+ @recording_url = 'recording_url'
98
+ @recording_duration = 0
99
+
100
+ post "/zestphone/providers/twilio/calls/#{@call.id}/child_detached",
101
+ DialCallSid: @child_call.sid,
102
+ DialCallStatus: 'completed',
103
+ RecordingUrl: @recording_url,
104
+ RecordingDuration: @recording_duration
105
+ end
106
+
107
+ it 'does not terminate the child call' do
108
+ @child_call.reload
109
+ @child_call.should_not be_terminated
110
+ end
111
+ end
112
+ end
113
+
114
+ describe 'When the child call is unanswered' do
115
+ before do
116
+ call = create :active_agent_leg
117
+ @connecting_call = create :connecting_call, conversation: call.conversation, sid: nil
118
+ @sid = '123'
119
+
120
+ post "/zestphone/providers/twilio/calls/#{call.id}/child_detached",
121
+ DialCallStatus: 'no-answer',
122
+ DialCallSid: @sid
123
+ end
124
+
125
+ it 'sets the sid of the child call' do
126
+ @connecting_call.reload.sid.should == @sid
127
+ end
128
+
129
+ it 'sets the participant call state to no_answer' do
130
+ @connecting_call.reload
131
+ @connecting_call.should be_terminated
132
+ end
133
+
134
+ it 'returns an empty TwiML response (whisper tone)' do
135
+ response.body.should be_hangup
136
+ end
137
+ end
138
+
139
+ describe 'When the child call fails' do
140
+ before do
141
+ call = create :active_agent_leg
142
+ @connecting_call = create :connecting_call, conversation: call.conversation, sid: nil
143
+ @sid = '123'
144
+
145
+ post "/zestphone/providers/twilio/calls/#{call.id}/child_detached",
146
+ DialCallStatus: 'failed',
147
+ DialCallSid: @sid
148
+ end
149
+
150
+ it 'sets the sid of the child call' do
151
+ @connecting_call.reload.sid.should == @sid
152
+ end
153
+
154
+ it 'sets the participant call state to call_failed' do
155
+ @connecting_call.reload
156
+ @connecting_call.should be_terminated
157
+ end
158
+
159
+ it 'returns an empty TwiML response (whisper tone)' do
160
+ response.body.should be_hangup
161
+ end
162
+ end
163
+
164
+ describe 'When the child call is busy' do
165
+ before do
166
+ call = create :active_agent_leg
167
+ @connecting_call = create :connecting_call, conversation: call.conversation, sid: nil
168
+ @sid = '123'
169
+
170
+ post "/zestphone/providers/twilio/calls/#{call.id}/child_detached",
171
+ DialCallStatus: 'busy',
172
+ DialCallSid: @sid
173
+ end
174
+
175
+ it 'sets the sid of the child call' do
176
+ @connecting_call.reload.sid.should == @sid
177
+ end
178
+
179
+ it 'sets the participant call state to busy' do
180
+ @connecting_call.reload
181
+ @connecting_call.should be_terminated
182
+ end
183
+
184
+ it 'returns an empty TwiML response (whisper tone)' do
185
+ response.body.should be_hangup
186
+ end
187
+ end
188
+
189
+ describe 'Given a one step transfer' do
190
+ context 'for a completed call' do
191
+ before do
192
+ agent = create :agent
193
+ @call = create :one_step_transfer_call, agent: agent
194
+ participant1 = create :in_progress_call, conversation: @call.conversation
195
+ create :connecting_call, conversation: @call.conversation
196
+
197
+ post "/zestphone/providers/twilio/calls/#{@call.id}/child_detached",
198
+ DialCallSid: participant1.sid,
199
+ DialCallStatus: 'completed'
200
+ end
201
+
202
+ it 'returns an empty TwiML response (whisper tone)' do
203
+ response.body.should be_hangup
204
+ end
205
+ end
206
+
207
+ context 'for an unanswered call' do
208
+ before do
209
+ @conversation = create :one_step_transferring_conversation
210
+ @agent = @conversation.active_agent_leg.agent
211
+
212
+ post "/zestphone/providers/twilio/calls/#{@conversation.customer.id}/child_detached",
213
+ DialCallStatus: 'no-answer'
214
+ end
215
+
216
+ it 'renders the voicemails/new twiml' do
217
+ xml = Nokogiri::XML response.body
218
+ say = xml.at '/Response/Say'
219
+ say.text.should =~ /at extension #{@agent.phone_ext}/i
220
+ say.text.should =~ /record your message/i
221
+ record = xml.at '/Response/Record'
222
+ record.attributes['action'].value.should == "/zestphone/providers/twilio/calls/#{@conversation.customer.id}/voicemail?csr_id=#{@agent.csr_id}"
223
+
224
+ end
225
+ end
226
+ end
227
+
228
+ describe 'Given a RONAed call' do
229
+ before do
230
+ conversation = create :rona_conversation
231
+ @customer_leg = conversation.customer
232
+ agent_leg = conversation.active_agent_leg
233
+
234
+ post "/zestphone/providers/twilio/calls/#{@customer_leg.id}/child_detached",
235
+ DialCallSid: agent_leg.sid,
236
+ DialCallStatus: 'no-answer'
237
+ end
238
+
239
+ it 'enqueues the call into the inbound queue' do
240
+ xml = Nokogiri::XML response.body
241
+ enqueue = xml.at '/Response/Enqueue'
242
+ enqueue.text.should == 'inbound'
243
+ enqueue.attributes['waitUrl'].value
244
+ .should =~ %r{/zestphone/providers/twilio/inbound_calls/wait_music$}
245
+ enqueue.attributes['waitUrlMethod'].value.should == 'GET'
246
+ enqueue.attributes['action'].value
247
+ .should == "/zestphone/providers/twilio/calls/#{@customer_leg.id}/leave_queue"
248
+ end
249
+ end