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,243 @@
1
+ require 'spec_helper'
2
+
3
+ module Telephony
4
+ describe InboundConversationQueue do
5
+ describe '.play_message' do
6
+ before do
7
+ @count = Conversation.count
8
+ @from = '111-111-1111'
9
+ @to = '222-222-2222'
10
+ @call_sid = "call_sid"
11
+
12
+ @conversation = InboundConversationQueue.play_message From: @from,
13
+ To: @to,
14
+ CallSid: @call_sid
15
+ end
16
+
17
+ it 'creates an inbound conversation' do
18
+ Conversation.count.should == @count + 1
19
+ conversation = Conversation.last
20
+ conversation.should be_inbound
21
+ end
22
+
23
+ it "sets the conversation's number to the called number" do
24
+ conversation = Conversation.last
25
+ conversation.number.should == @to
26
+ end
27
+
28
+ it "sets the conversation's caller id to the called number" do
29
+ conversation = Conversation.last
30
+ conversation.caller_id.should == @to
31
+ end
32
+
33
+ it 'connects the conversation' do
34
+ conversation = Conversation.last
35
+ conversation.should be_playing_message
36
+ end
37
+
38
+ it 'creates the initial leg of the conversation' do
39
+ conversation = Conversation.last
40
+ conversation.should have(1).call
41
+ call = conversation.calls.first
42
+ call.number.should == @from
43
+ call.sid.should == @call_sid
44
+ end
45
+
46
+ it 'answers the initial leg' do
47
+ conversation = Conversation.last
48
+ conversation.should have(1).call
49
+ call = conversation.calls.first
50
+ call.should be_in_progress
51
+ end
52
+ end
53
+
54
+ describe '.play_closed_greeting' do
55
+ before do
56
+ @count = Conversation.count
57
+ @from = '111-111-1111'
58
+ @to = '222-222-2222'
59
+ @call_sid = "call_sid"
60
+
61
+ @conversation = InboundConversationQueue.play_closed_greeting From: @from,
62
+ To: @to,
63
+ CallSid: @call_sid
64
+ end
65
+
66
+ it 'creates an inbound conversation' do
67
+ Conversation.count.should == @count + 1
68
+ conversation = Conversation.last
69
+ conversation.should be_inbound
70
+ end
71
+
72
+ it "sets the conversation's number to the called number" do
73
+ conversation = Conversation.last
74
+ conversation.number.should == @to
75
+ end
76
+
77
+ it "sets the conversation's caller id to the called number" do
78
+ conversation = Conversation.last
79
+ conversation.caller_id.should == @to
80
+ end
81
+
82
+ it 'sets the conversation to closed greetings' do
83
+ conversation = Conversation.last
84
+ conversation.should be_terminated
85
+ end
86
+
87
+ it 'creates customer leg of the conversation' do
88
+ conversation = Conversation.last
89
+ conversation.should have(1).call
90
+ call = conversation.calls.first
91
+ call.number.should == @from
92
+ call.sid.should == @call_sid
93
+ call.should be_terminated
94
+ end
95
+ end
96
+
97
+ describe '.reject' do
98
+ before do
99
+ @count = Conversation.count
100
+ @from = '111-111-1111'
101
+ @to = '222-222-2222'
102
+ @call_sid = "call_sid"
103
+
104
+ @conversation = InboundConversationQueue.reject From: @from,
105
+ To: @to,
106
+ CallSid: @call_sid
107
+ end
108
+
109
+ it 'creates an inbound conversation' do
110
+ Conversation.count.should == @count + 1
111
+ conversation = Conversation.last
112
+ conversation.should be_inbound
113
+ end
114
+
115
+ it "sets the conversation's number to the called number" do
116
+ conversation = Conversation.last
117
+ conversation.number.should == @to
118
+ end
119
+
120
+ it "sets the conversation's caller id to the called number" do
121
+ conversation = Conversation.last
122
+ conversation.caller_id.should == @to
123
+ end
124
+
125
+ it 'sets the conversation to closed greetings' do
126
+ conversation = Conversation.last
127
+ conversation.should be_terminated
128
+ end
129
+
130
+ it 'creates customer leg' do
131
+ conversation = Conversation.last
132
+ conversation.should have(1).call
133
+ call = conversation.calls.first
134
+ call.number.should == @from
135
+ call.sid.should == @call_sid
136
+ call.should be_terminated
137
+ end
138
+
139
+ it 'creates a rejected event for the customer leg' do
140
+ Telephony::Events::Reject.where(call_id: Telephony::Call.last.id).should be_exists
141
+ end
142
+ end
143
+
144
+ describe '.dequeue' do
145
+ context 'given a queue with a conversation' do
146
+ before do
147
+ @conversation = create :enqueued_conversation
148
+ InboundConversationQueue.should_receive(:oldest_queued_conversation).and_return(@conversation)
149
+ @agent = create :available_agent, csr_id: 123
150
+ Telephony
151
+ .provider
152
+ .stub(:redirect_to_inbound_connect)
153
+ end
154
+
155
+ it 'puts the agent on a call' do
156
+ @inbound_conversation = InboundConversationQueue.dequeue 123
157
+
158
+ @agent.reload.should be_on_a_call
159
+ end
160
+
161
+ it 'redirects the customer inbound connect' do
162
+ @conversation.customer.should_receive(:redirect_to_inbound_connect)
163
+
164
+ @inbound_conversation = InboundConversationQueue.dequeue 123
165
+ end
166
+
167
+ it 'dequeues the next inbound call' do
168
+ @inbound_conversation = InboundConversationQueue.dequeue 123
169
+
170
+ @inbound_conversation[:id].should == @conversation.id
171
+ @inbound_conversation[:customer_number].should == @conversation.customer.number
172
+ @inbound_conversation[:pop_url].should be_nil
173
+ end
174
+
175
+ context "given a call with an associated pop url" do
176
+ before do
177
+ finder = mock()
178
+ finder.stub(:find).with(@conversation.customer.sanitized_number).and_return('/foo')
179
+ Telephony.pop_url_finder = finder
180
+ @inbound_conversation = InboundConversationQueue.dequeue 123
181
+ end
182
+
183
+ after do
184
+ Telephony.pop_url_finder = nil
185
+ end
186
+
187
+ it "sets the pop url" do
188
+ JSON(@inbound_conversation.to_json)["pop_url"].should == "/foo"
189
+ end
190
+ end
191
+ end
192
+
193
+ context 'given an agent on a call' do
194
+ before do
195
+ @agent = create :on_a_call_agent, csr_id: 123
196
+ end
197
+
198
+ it 'raises an agent error exception' do
199
+ expect {
200
+ InboundConversationQueue.dequeue 123
201
+ }.to raise_error(Telephony::Error::AgentOnACall)
202
+ end
203
+ end
204
+
205
+ context 'given an empty queue' do
206
+ it 'raises an empty queue exception' do
207
+ agent = create :available_agent, csr_id: 123
208
+
209
+ expect {
210
+ InboundConversationQueue.dequeue 123
211
+ }.to raise_error(Telephony::Error::QueueEmpty)
212
+ end
213
+ end
214
+ end
215
+
216
+ describe '.oldest_queued_conversation' do
217
+ before do
218
+ @conversation2 = create :enqueued_conversation
219
+ @conversation1 = create :enqueued_conversation, created_at: (@conversation2.created_at - 1.second)
220
+ end
221
+
222
+ it 'should set the state of the dequeued call to connecting' do
223
+ InboundConversationQueue.oldest_queued_conversation
224
+ @conversation1.reload.should be_connecting
225
+ end
226
+
227
+ it 'should return the oldest first' do
228
+ InboundConversationQueue.oldest_queued_conversation.should == @conversation1
229
+ end
230
+
231
+ it 'should return the newest second' do
232
+ InboundConversationQueue.oldest_queued_conversation.should == @conversation1
233
+ InboundConversationQueue.oldest_queued_conversation.should == @conversation2
234
+ end
235
+
236
+ it 'should return nothing when it is empty' do
237
+ InboundConversationQueue.oldest_queued_conversation.should == @conversation1
238
+ InboundConversationQueue.oldest_queued_conversation.should == @conversation2
239
+ InboundConversationQueue.oldest_queued_conversation.should == nil
240
+ end
241
+ end
242
+ end
243
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ module Telephony
4
+ describe PlayableListener do
5
+ describe "#valid?" do
6
+ it "fails without a csr id" do
7
+ listener = build :playable_listener, csr_id: nil
8
+
9
+ listener.should_not be_valid
10
+ listener.should have(1).error_on(:csr_id)
11
+ end
12
+
13
+ it "fails without a playable id" do
14
+ listener = build :playable_listener, playable_id: nil
15
+
16
+ listener.should_not be_valid
17
+ listener.should have(1).error_on(:playable_id)
18
+ end
19
+ end
20
+
21
+ describe '.recent' do
22
+ context 'given playable listeners for multiple playables' do
23
+ before do
24
+ playable = create :voicemail
25
+ create :playable_listener,
26
+ playable_id: playable.id,
27
+ created_at: 2.days.ago
28
+ @most_recent_listener = create :playable_listener,
29
+ playable_id: playable.id,
30
+ created_at: 1.day.ago
31
+
32
+ @playable_listeners = PlayableListener.recent playable_ids: [playable]
33
+ end
34
+
35
+ it 'returns the most recent listener for each playable' do
36
+ @playable_listeners.should_not be_empty
37
+ @playable_listeners[0].should == @most_recent_listener
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ module Telephony
4
+ describe PusherEventPublisher do
5
+ describe ".publish", :vcr do
6
+ let(:event) do
7
+ {
8
+ channel: 'test',
9
+ name: 'test_event',
10
+ data: { key1: 'value' }
11
+ }
12
+ end
13
+
14
+ it "queues the event if using delayed_jobs" do
15
+ DELAYED_JOB.should_receive(:enqueue)
16
+ PusherEventPublisher.publish({})
17
+ end
18
+
19
+ it "asks Pusher to publish the event" do
20
+ VCR.use_cassette "Pusher to publish the event", match_requests_on: [:path] do
21
+ PusherEventPublisher.publish(event)
22
+
23
+ request = VCR.current_cassette.serializable_hash['http_interactions'][0]['request']
24
+
25
+ channel, name, data = event.values_at :channel, :name, :data
26
+ body = JSON request['body']['string']
27
+ body.should include('channels' => [channel])
28
+ body.should include('name' => name)
29
+
30
+ request_data = JSON body['data']
31
+ request_data.should == data.stringify_keys
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+
3
+ module Telephony
4
+ describe Recording do
5
+ end
6
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ module Telephony
4
+ describe Voicemail do
5
+ describe "#valid?" do
6
+ before do
7
+ @voicemail = build :voicemail, csr_id: nil
8
+ end
9
+
10
+ it "fails without a csr id" do
11
+ @voicemail.should_not be_valid
12
+ @voicemail.should have(1).error_on(:csr_id)
13
+ end
14
+ end
15
+
16
+ describe '#as_json' do
17
+ before do
18
+ @voicemail = create :voicemail
19
+
20
+ @as_json = @voicemail.as_json
21
+ end
22
+
23
+ it 'includes its id' do
24
+ @as_json['id'].should == @voicemail.id
25
+ end
26
+
27
+ it "includes its conversations' loan id" do
28
+ @as_json['loan_id'].should == @voicemail.call.conversation.loan_id
29
+ end
30
+
31
+ it 'includes its creation timestamp' do
32
+ @as_json['created_at'].should == @voicemail.created_at
33
+ end
34
+
35
+ it 'includes its duration' do
36
+ @as_json['duration'].should == @voicemail.duration
37
+ end
38
+
39
+ it 'includes its url' do
40
+ @as_json['url'].should == @voicemail.url
41
+ end
42
+
43
+ it "includes its transferer's id" do
44
+ @as_json['transferer_id'].should == @voicemail.call.conversation.initiator_id
45
+ end
46
+
47
+ it "includes its transferee's id" do
48
+ @as_json['transferee_id'].should == @voicemail.csr_id
49
+ end
50
+ end
51
+
52
+ describe '.filter' do
53
+ context 'by default' do
54
+ before do
55
+ @page = 1
56
+
57
+ @voicemails = Voicemail.filter page: @page
58
+ end
59
+
60
+ it 'returns the given page of voicemails' do
61
+ @voicemails.current_page.should == @page
62
+ end
63
+
64
+ it 'includes the total count of voicemails' do
65
+ @voicemails.total_count.should == Voicemail.count
66
+ end
67
+ end
68
+
69
+ context 'given a CSR id' do
70
+ before do
71
+ voicemails = create_list :voicemail, 3
72
+ @csr_id = voicemails.first.csr_id
73
+
74
+ @voicemails = Voicemail.filter csr_id: @csr_id
75
+ end
76
+
77
+ it 'returns only voicemails left for that CSR' do
78
+ @voicemails.should_not be_empty
79
+ @voicemails.each do |voicemail|
80
+ voicemail.transferee_id.should == @csr_id
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ describe '.most_recent' do
87
+ it "orders by created_at DESC" do
88
+ voicemails = create_list :voicemail, 3
89
+ voicemails[0].update_attribute(:created_at, 100.days.ago)
90
+ voicemails[1].update_attribute(:created_at, 3.days.ago)
91
+ voicemails[2].update_attribute(:created_at, 20.days.ago)
92
+ Voicemail.most_recent.all.should == [voicemails[1], voicemails[2], voicemails[0]]
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ module Telephony
4
+ describe AgentObserver do
5
+ before do
6
+ ActiveRecord::Base.observers.enable 'Telephony::AgentObserver'
7
+ AgentObserver.instance
8
+ end
9
+
10
+ describe "#after_save" do
11
+ before do
12
+ @agent = create :offline_agent
13
+ @agent.should_receive(:publish_status_change)
14
+ end
15
+
16
+ it "asks the agent to publish its status change" do
17
+ @agent.available!
18
+ end
19
+ end
20
+ end
21
+ end