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,108 @@
1
+ require 'spec_helper'
2
+
3
+ module Telephony
4
+ describe 'Receive an inbound call', :vcr do
5
+ before do
6
+ @from = '555-555-1234'
7
+ @to = '555-555-1235'
8
+ end
9
+
10
+ context "offices are open" do
11
+ before do
12
+ Telephony::OFFICE_HOURS.stub(:open?).and_return true
13
+ @count = Conversation.count
14
+ post '/zestphone/providers/twilio/inbound_calls', From: @from, To: @to
15
+ end
16
+
17
+ it 'plays the open hours greeting' do
18
+ xml = Nokogiri::XML response.body
19
+ play = xml.at('/Response/Play')
20
+ play.text.should =~ /monkey\.mp3$/
21
+ end
22
+
23
+ it 'creates a new conversation' do
24
+ Conversation.count.should == @count + 1
25
+ end
26
+ end
27
+
28
+ context "offices are closed" do
29
+ before do
30
+ Telephony::OFFICE_HOURS.stub(:open?).and_return false
31
+ post '/zestphone/providers/twilio/inbound_calls', From: @from, To: @to
32
+ end
33
+
34
+ it "plays the closed hours greeting" do
35
+ xml = Nokogiri::XML response.body
36
+ play = xml.at('/Response/Play')
37
+ play.text.should =~ /cowbell\.mp3$/
38
+ end
39
+ end
40
+
41
+ context "number is on the reject list" do
42
+ before do
43
+ Telephony::BlacklistedNumber.create number: Telephony.americanize(@from)
44
+ post '/zestphone/providers/twilio/inbound_calls', From: @from, To: @to
45
+ end
46
+
47
+ it "rejects the call" do
48
+ xml = Nokogiri::XML response.body
49
+ reject = xml.at('/Response/Reject')
50
+ reject.should be_present
51
+ end
52
+ end
53
+ end
54
+
55
+ describe 'Enqueue an inbound call', :vcr do
56
+ context 'when a customer hangs up while listening our greetings message' do
57
+ before do
58
+ @call = create :call
59
+ @call.conversation.play_message
60
+ post "/zestphone/providers/twilio/inbound_calls/#{@call.conversation_id}/enqueue",
61
+ CallStatus: 'completed'
62
+ end
63
+
64
+ it 'terminates the call' do
65
+ @call.reload.should be_terminated
66
+ end
67
+
68
+ it 'renders a whisper tone' do
69
+ xml = Nokogiri::XML response.body
70
+ xml.at('/Response').text.should be_empty
71
+ end
72
+ end
73
+
74
+ context 'when a customer stays on the line' do
75
+ before do
76
+ @call = create :call
77
+ @call.conversation.play_message
78
+ post "/zestphone/providers/twilio/inbound_calls/#{@call.conversation_id}/enqueue",
79
+ CallStatus: 'in-progress'
80
+ end
81
+
82
+ it 'enqueues the conversation' do
83
+ @call.conversation.reload.should be_enqueued
84
+ end
85
+
86
+ it 'renders the enqueue template' do
87
+ xml = Nokogiri::XML response.body
88
+ enqueue = xml.at('/Response/Enqueue')
89
+ enqueue.text.should == 'inbound'
90
+ enqueue.attributes['action'].value
91
+ .should == "/zestphone/providers/twilio/calls/#{@call.id}/leave_queue"
92
+ end
93
+ end
94
+
95
+ context 'when a customer gets the wait music' do
96
+ before do
97
+ get "/zestphone/providers/twilio/inbound_calls/wait_music"
98
+ end
99
+
100
+ it 'should play the correct file' do
101
+ xml = Nokogiri::XML response.body
102
+ play = xml.at('/Response/Play')
103
+ play.text.should == 'https://example.com/wait_music.wav'
104
+ play.attributes['loop'].value.should == '0'
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Enqueued calls wait music' do
4
+ before do
5
+ get '/zestphone/providers/twilio/inbound_calls/wait_music'
6
+ end
7
+
8
+ it 'returns TwiML for playing wait music' do
9
+ xml = Nokogiri::XML response.body
10
+ play = xml.at('/Response/Play')
11
+ play.text.should =~ /\.wav$/
12
+ end
13
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Leaving a voicemail for a callee that didn't answer" do
4
+ before do
5
+ Telephony::Providers::Twilio::VoicemailsController.any_instance.stub(:verify_twilio_request).and_return(true)
6
+ @conversation = create :one_step_transferring_conversation
7
+ @call = @conversation.calls.first
8
+ agent_call = @conversation.calls.last
9
+ @agent = agent_call.agent
10
+
11
+ post "/zestphone/providers/twilio/calls/#{@call.id}/child_detached",
12
+ DialCallStatus: 'no-answer',
13
+ DialCallSid: agent_call.sid
14
+ end
15
+
16
+ it 'returns TwiML for recording a voicemail' do
17
+ xml = Nokogiri::XML response.body
18
+ say = xml.at '/Response/Say'
19
+ say.text.should =~ /at extension #{@agent.phone_ext}/i
20
+ say.text.should =~ /record your message/i
21
+ record = xml.at '/Response/Record'
22
+ record.attributes['action'].value.should == "/zestphone/providers/twilio/calls/#{@call.id}/voicemail?csr_id=#{@agent.csr_id}"
23
+ end
24
+ end
25
+
26
+ describe 'Leaving a voicemail for a completed call' do
27
+ before do
28
+ Telephony::Providers::Twilio::VoicemailsController.any_instance.stub(:verify_twilio_request).and_return(true)
29
+ agent = create :agent
30
+ original_call = create :terminated_call, agent: agent
31
+ @conversation = original_call.conversation
32
+ call = create :in_progress_call, conversation: original_call.conversation
33
+ @child_call = create :in_progress_call, conversation: original_call.conversation
34
+
35
+ post "/zestphone/providers/twilio/calls/#{call.id}/child_detached",
36
+ DialCallStatus: 'completed',
37
+ DialCallSid: @child_call.sid,
38
+ DialCallDuration: 1
39
+ end
40
+
41
+ it 'returns a TwiML hangup' do
42
+ response.body.should be_hangup
43
+ end
44
+
45
+ it 'sets the agent call to terminated' do
46
+ @child_call.reload.should be_terminated
47
+ end
48
+ end
49
+
50
+ describe 'Saving a voicemail' do
51
+ before do
52
+ Telephony::Providers::Twilio::VoicemailsController.any_instance.stub(:verify_twilio_request).and_return(true)
53
+ agent = create :agent
54
+ @call = create :call, agent: agent
55
+ @csr_id = 1
56
+ @recording_url = 'recording_url'
57
+ @recording_duration = 1
58
+
59
+ post "/zestphone/providers/twilio/calls/#{@call.id}/voicemail",
60
+ { csr_id: @csr_id,
61
+ RecordingUrl: @recording_url,
62
+ RecordingDuration: @recording_duration}
63
+ end
64
+
65
+ it 'creates a voicemail for the call' do
66
+ @call.reload
67
+ voicemail = @call.voicemail
68
+ voicemail.should be
69
+ voicemail.csr_id.should == @csr_id
70
+ voicemail.url.should == @recording_url
71
+ voicemail.duration.should == @recording_duration
72
+ end
73
+
74
+ it 'returns a success response' do
75
+ response.code.should == '200'
76
+ response.body.should be_whisper_tone
77
+ end
78
+ end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Search for conversations' do
4
+ before do
5
+ agent = create :agent
6
+ conversation = create :conversation
7
+ create :conversation, created_at: (conversation.created_at - 1.second)
8
+ create :conversation_connect_event, conversation: conversation
9
+
10
+ call = create :call_with_recording,
11
+ conversation: conversation,
12
+ agent: agent
13
+ create :customer_leg,
14
+ conversation: conversation,
15
+ number: '555-555-1111'
16
+
17
+ create :voicemail,
18
+ call: call
19
+
20
+ attributes = {}
21
+
22
+ xhr :get,
23
+ '/zestphone/conversations/search',
24
+ attributes
25
+
26
+ json = JSON.parse(response.body)
27
+ conversations = json['conversations']
28
+ @total_count = json['total_count']
29
+
30
+ @conversation = conversations.first
31
+
32
+ @call = @conversation['calls'].first
33
+ @voicemail = @call['voicemail']
34
+ @agent = @call['agent']
35
+ @event = @conversation['events'].first
36
+ @recording = @call['recordings'].first
37
+ end
38
+
39
+ it 'returns conversations as JSON' do
40
+ @conversation.should include('id')
41
+ @conversation.should include('created_at')
42
+ @conversation.should include('loan_id')
43
+ @conversation.should include('state')
44
+ @conversation.should include('number')
45
+ @conversation.should include('customer_number')
46
+ @conversation.should include('conversation_type')
47
+ @conversation.should include('calls')
48
+ @conversation.should include('events')
49
+ end
50
+
51
+ it 'returns calls as JSON' do
52
+ @call.should include('id')
53
+ @call.should include('number')
54
+ @call.should include('sid')
55
+ @call.should include('state')
56
+ @call.should include('created_at')
57
+ @call.should include('agent')
58
+ @call.should include('voicemail')
59
+ @call.should include('recordings')
60
+ end
61
+
62
+ it 'returns events as JSON' do
63
+ @event.should include('id')
64
+ @event.should include('type')
65
+ @event.should include('conversation_id')
66
+ @event.should include('conversation_state')
67
+ @event.should include('call_id')
68
+ @event.should include('call_state')
69
+ @event.should include('agent')
70
+ @event.should include('elapsed_seconds')
71
+ @event.should include('created_at')
72
+ end
73
+
74
+ it 'returns an agent as JSON' do
75
+ @agent.should include('id')
76
+ @agent.should include('csr_id')
77
+ @agent.should include('name')
78
+ @agent.should include('status')
79
+ @agent.should include('phone_type')
80
+ @agent.should include('phone_number')
81
+ @agent.should include('sip_number')
82
+ end
83
+
84
+ it 'returns a voicemail as JSON' do
85
+ @voicemail.should include('id')
86
+ @voicemail.should include('duration')
87
+ @voicemail.should include('url')
88
+ end
89
+
90
+ it 'returns recordings as JSON' do
91
+ @recording.should include('id')
92
+ @recording.should include('duration')
93
+ @recording.should include('url')
94
+ end
95
+
96
+ it 'returns a total_count' do
97
+ count = Telephony::Conversation.count
98
+
99
+ @total_count.should == count
100
+ end
101
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Initiating a transfer' do
4
+ before do
5
+ @conversation = create :conversation, state: :in_progress
6
+ create :active_agent_leg, conversation: @conversation
7
+ customer = create :in_progress_call, conversation: @conversation
8
+ @agent = create :available_agent
9
+
10
+ Telephony
11
+ .provider
12
+ .should_receive(:redirect_to_dial)
13
+ .with(customer.id, customer.sid)
14
+ .and_return(true)
15
+ @transfer_type = 'one_step'
16
+
17
+ post "/zestphone/conversations/#{@conversation.id}/transfers",
18
+ transfer_type: @transfer_type,
19
+ transfer_id: @agent.csr_id
20
+ end
21
+
22
+ it 'transfers the call' do
23
+ @conversation.reload
24
+ @conversation.should be_one_step_transferring
25
+ end
26
+
27
+ it 'returns a successful response' do
28
+ response.should be_success
29
+ end
30
+
31
+ it 'returns an empty JSON object' do
32
+ json = JSON response.body
33
+ json.should be_empty
34
+ end
35
+ end
36
+
37
+ describe 'Failing to transfer' do
38
+ before do
39
+ conversation = create :conversation, state: :in_progress
40
+ create :active_agent_leg, conversation: conversation
41
+ create :in_progress_call, conversation: conversation
42
+ agent = create :available_agent
43
+
44
+ Telephony
45
+ .provider
46
+ .stub(:redirect_to_conference)
47
+ .and_raise(Telephony::Error::Connection.new('a failure message'))
48
+
49
+ post "/zestphone/conversations/#{conversation.id}/transfers",
50
+ transfer_id: agent.csr_id
51
+ end
52
+
53
+ it 'return a 422 failure response' do
54
+ response.code.should == "422"
55
+ end
56
+
57
+ it 'returns an error message as JSON' do
58
+ json = JSON response.body
59
+ json.should include('errors')
60
+ errors = json['errors']
61
+ errors.should have(2).errors
62
+ errors[0].should == 'Transfer failed. Please try again in a few seconds.'
63
+ errors[1].should == 'a failure message'
64
+ end
65
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'GET /voicemails' do
4
+ before do
5
+ create_list :voicemail, 3
6
+
7
+ get '/zestphone/voicemails'
8
+ end
9
+
10
+ it 'returns all voicemails as JSON' do
11
+ json = JSON response.body
12
+ voicemails = json['items']
13
+ voicemails.should have(Telephony::Voicemail.count).voicemails
14
+ voicemails.each do |voicemail|
15
+ %w(id
16
+ url
17
+ created_at
18
+ duration
19
+ loan_id
20
+ transferer_id
21
+ transferee_id).each do |attribute|
22
+ voicemail.should include(attribute)
23
+ end
24
+ end
25
+ json['total_count'].should == Telephony::Voicemail.count
26
+ end
27
+
28
+ end
29
+
30
+ describe "GET /voicemails ordering" do
31
+ it 'orders voicemails by most recent' do
32
+ voicemails = create_list :voicemail, 3
33
+ voicemails[0].update_attribute(:created_at, 100.days.ago)
34
+ voicemails[1].update_attribute(:created_at, 3.days.ago)
35
+ voicemails[2].update_attribute(:created_at, 20.days.ago)
36
+
37
+ get '/zestphone/voicemails'
38
+
39
+ json = JSON response.body
40
+ json["items"].map { |v| v["id"] }.should == [voicemails[1].id, voicemails[2].id, voicemails[0].id]
41
+ end
42
+ end
43
+
44
+ describe 'GET /voicemails?csr_id=' do
45
+ before do
46
+ voicemails = create_list :voicemail, 3
47
+ @csr_id = voicemails.first.csr_id
48
+
49
+ get "/zestphone/voicemails?csr_id=#{@csr_id}"
50
+ end
51
+
52
+ it 'returns only voicemails left for the CSR as JSON' do
53
+ json = JSON response.body
54
+ items = json['items']
55
+ items.should have(1).voicemail
56
+ items[0]['transferee_id'].should == @csr_id
57
+ end
58
+ end
@@ -0,0 +1,27 @@
1
+ # Configure Rails Environment
2
+ ENV["RAILS_ENV"] = "test"
3
+
4
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
5
+ require "rspec/rails"
6
+ require "timecop"
7
+ require "webmock/rspec"
8
+
9
+ ENGINE_RAILS_ROOT=File.join(File.dirname(__FILE__),'../')
10
+
11
+ # Load support files
12
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
13
+
14
+ RSpec.configure do |config|
15
+ config.use_transactional_fixtures = true
16
+ config.color_enabled = true
17
+ config.render_views
18
+ config.treat_symbols_as_metadata_keys_with_true_values = true
19
+
20
+ config.extend VCR::RSpec::Macros
21
+
22
+ config.include PusherSignatureHelper, :type => :controller
23
+
24
+ config.before do
25
+ ActiveRecord::Base.observers.disable :all
26
+ end
27
+ end