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,387 @@
1
+ require 'spec_helper'
2
+
3
+ module Telephony
4
+ describe ConversationStateMachine do
5
+ describe '#state' do
6
+ before do
7
+ @conversation = create :conversation
8
+ end
9
+
10
+ it 'defaults to "initiated"' do
11
+ @conversation.state.should == 'initiated'
12
+ end
13
+ end
14
+
15
+ describe '#connect!' do
16
+ before do
17
+ @conversation = create :conversation
18
+ @conversation.connect!
19
+ end
20
+
21
+ it 'transitions to "connecting"' do
22
+ @conversation.state.should == 'connecting'
23
+ end
24
+
25
+ it 'logs a connect event' do
26
+ event = Events::Connect.last
27
+ event.should be
28
+ event.conversation_id.should == @conversation.id
29
+ event.conversation_state.should == @conversation.state
30
+ end
31
+ end
32
+
33
+ describe '#start!' do
34
+ context 'from connecting' do
35
+ before do
36
+ @conversation = create :connecting_conversation
37
+ @conversation.start!
38
+ end
39
+
40
+ it 'transitions to "in_progress"' do
41
+ @conversation.should be_in_progress
42
+ end
43
+
44
+ it 'logs a start event' do
45
+ event = Events::Start.last
46
+ event.should be
47
+ end
48
+ end
49
+ end
50
+
51
+ describe '#initiate_one_step_transfer!' do
52
+ context "from in_progress" do
53
+ before do
54
+ @conversation = create :in_progress_conversation_with_calls
55
+ @conversation.initiate_one_step_transfer!
56
+ end
57
+
58
+ it 'transitions to "one_step_transferring"' do
59
+ @conversation.state.should == 'one_step_transferring'
60
+ end
61
+
62
+ it 'logs a one step transfer initiated event' do
63
+ event = Events::InitiateOneStepTransfer.last
64
+ event.should be
65
+ end
66
+ end
67
+
68
+ context "from in_progress_hold" do
69
+ it "transitions to 'one_step_transferring'" do
70
+ conversation = create :in_progress_hold_conversation_with_calls
71
+
72
+ conversation.initiate_one_step_transfer!
73
+ conversation.state.should == "one_step_transferring"
74
+ end
75
+ end
76
+ end
77
+
78
+ describe '#complete_one_step_transfer!' do
79
+ before do
80
+ @conversation = create :in_progress_conversation_with_calls
81
+ @conversation.initiate_one_step_transfer!
82
+ @conversation.complete_one_step_transfer!
83
+ end
84
+
85
+ it 'transitions to "in_progress"' do
86
+ @conversation.state.should == 'in_progress'
87
+ end
88
+
89
+ it 'logs a one step transfer completed event' do
90
+ event = Events::CompleteOneStepTransfer.last
91
+ event.should be
92
+ end
93
+ end
94
+
95
+ describe '#fail_one_step_transfer!' do
96
+ before do
97
+ @conversation = create :in_progress_conversation_with_calls
98
+ @conversation.initiate_one_step_transfer!
99
+ @conversation.active_agent_leg.terminate!
100
+ @conversation.fail_one_step_transfer!
101
+ end
102
+
103
+ it 'transitions to "leaving_voicemail"' do
104
+ @conversation.state.should == 'leaving_voicemail'
105
+ end
106
+
107
+ it 'logs a one step transfer failed event' do
108
+ event = Events::FailOneStepTransfer.last
109
+ event.should be
110
+ end
111
+ end
112
+
113
+ describe '#initiate_two_step_transfer!' do
114
+ context "from 'in_progress'" do
115
+ before do
116
+ @conversation = create :in_progress_conversation_with_calls
117
+ @conversation.initiate_two_step_transfer!
118
+ end
119
+
120
+ it 'transitions to "two_step_transferring"' do
121
+ @conversation.state.should == 'two_step_transferring'
122
+ end
123
+
124
+ it 'logs a two step transfer initiated event' do
125
+ event = Events::InitiateTwoStepTransfer.last
126
+ event.should be
127
+ end
128
+ end
129
+
130
+ context "from 'in_progress_hold'" do
131
+ it "transitions to 'two_step_transferring_hold'" do
132
+ conversation = create :in_progress_hold_conversation_with_calls
133
+
134
+ conversation.initiate_two_step_transfer!
135
+ conversation.state.should == "two_step_transferring_hold"
136
+ end
137
+ end
138
+ end
139
+
140
+ describe '#complete_two_step_transfer!' do
141
+ context "from two_step_transferring" do
142
+ before do
143
+ @conversation = create :in_progress_conversation_with_calls
144
+ @conversation.initiate_two_step_transfer!
145
+ @conversation.complete_two_step_transfer!
146
+ end
147
+
148
+ it 'transitions to "in_progress_two_step_transfer"' do
149
+ @conversation.state.should == 'in_progress_two_step_transfer'
150
+ end
151
+
152
+ it 'logs a two step transfer completed event' do
153
+ event = Events::CompleteTwoStepTransfer.last
154
+ event.should be
155
+ end
156
+ end
157
+
158
+ context "from two_step_transferring_hold" do
159
+ before do
160
+ @conversation = create :two_step_transferring_hold_conversation_with_calls
161
+ @conversation.complete_two_step_transfer!
162
+ end
163
+
164
+ it 'transitions to "in_progress_two_step_transfer_hold"' do
165
+ @conversation.state.should == 'in_progress_two_step_transfer_hold'
166
+ end
167
+
168
+ it 'logs a two step transfer completed event' do
169
+ event = Events::CompleteTwoStepTransfer.last
170
+ event.should be
171
+ end
172
+ end
173
+ end
174
+
175
+ describe '#customer_left_two_step_transfer!' do
176
+ context "from 'in_progress_two_step_transfer' conversation" do
177
+ before do
178
+ @conversation = create :in_progress_two_step_transfer_with_calls
179
+ @conversation.customer_left_two_step_transfer!
180
+ end
181
+
182
+ it 'transitions to "agents_only"' do
183
+ @conversation.should be_agents_only
184
+ end
185
+
186
+ it 'logs a customer left two step transfer event' do
187
+ event = Events::CustomerLeftTwoStepTransfer.last
188
+ event.should be
189
+ end
190
+ end
191
+
192
+ context "from 'in_progress_two_step_transfer_hold' conversation" do
193
+ before do
194
+ @conversation = create :in_progress_two_step_transfer_hold_with_calls
195
+ @conversation.customer_left_two_step_transfer!
196
+ end
197
+
198
+ it 'transitions to "agents_only"' do
199
+ @conversation.should be_agents_only
200
+ end
201
+ end
202
+ end
203
+
204
+ describe '#leave_two_step_transfer!' do
205
+ context "from 'in_progress_two_step_transfer' conversation" do
206
+ before do
207
+ @conversation = create :in_progress_two_step_transfer_conversation
208
+ @conversation.leave_two_step_transfer!
209
+ end
210
+
211
+ it 'transitions to "in_progress"' do
212
+ @conversation.state.should == 'in_progress'
213
+ end
214
+
215
+ it 'logs a leave two step transfer event' do
216
+ event = Events::LeaveTwoStepTransfer.last
217
+ event.should be
218
+ end
219
+ end
220
+
221
+ context "from 'in_progress_two_step_transfer_hold' conversation" do
222
+ before do
223
+ @conversation = create :conversation, state: 'in_progress_two_step_transfer_hold'
224
+ @conversation.leave_two_step_transfer!
225
+ end
226
+
227
+ it 'transitions to "in_progress"' do
228
+ @conversation.state.should == 'in_progress_hold'
229
+ end
230
+ end
231
+ end
232
+
233
+ describe '#fail_two_step_transfer!' do
234
+ context "from 'two_step_transferring' conversation" do
235
+ before do
236
+ @conversation = create :in_progress_conversation_with_calls
237
+ @conversation.initiate_two_step_transfer!
238
+ @conversation.fail_two_step_transfer!
239
+ end
240
+
241
+ it 'transitions to "in_progress"' do
242
+ @conversation.state.should == 'in_progress'
243
+ end
244
+
245
+ it 'logs a two step transfer failed event' do
246
+ event = Events::FailTwoStepTransfer.last
247
+ event.should be
248
+ end
249
+ end
250
+
251
+ context "from 'two_step_transferring_hold' conversation" do
252
+ before do
253
+ @conversation = create :two_step_transferring_hold_conversation_with_calls
254
+ @conversation.fail_two_step_transfer!
255
+ end
256
+
257
+ it 'transitions to "in_progress"' do
258
+ @conversation.state.should == 'in_progress_hold'
259
+ end
260
+ end
261
+ end
262
+
263
+ describe '#leave_voicemail!' do
264
+ before do
265
+ @conversation = create :in_progress_conversation_with_calls
266
+ @conversation.leave_voicemail!
267
+ end
268
+
269
+ it 'transitions to "leaving_voicemail"' do
270
+ @conversation.state.should == 'leaving_voicemail'
271
+ end
272
+
273
+ it 'logs a leave voicemail event' do
274
+ event = Events::LeaveVoicemail.last
275
+ event.should be
276
+ end
277
+ end
278
+
279
+ describe '#terminate!' do
280
+ before do
281
+ @conversation = create :in_progress_conversation
282
+ @conversation.terminate!
283
+ end
284
+
285
+ it 'transitions to "terminated"' do
286
+ @conversation.state.should == 'terminated'
287
+ end
288
+
289
+ it 'logs a terminated event' do
290
+ event = Events::Terminate.last
291
+ event.should be
292
+ end
293
+ end
294
+
295
+ describe "#initiate_hold" do
296
+ context "given 'in_progress' conversation" do
297
+ before do
298
+ @conversation = create :in_progress_conversation
299
+ @conversation.initiate_hold!
300
+ end
301
+
302
+ it 'transitions to "initiating_hold"' do
303
+ @conversation.should be_initiating_hold
304
+ end
305
+ end
306
+
307
+ context "given 'in_progress_two_step_transfer' conversation" do
308
+ before do
309
+ @conversation = create :in_progress_two_step_transfer_conversation
310
+ @conversation.initiate_hold!
311
+ end
312
+
313
+ it 'transitions to "initiating_hold"' do
314
+ @conversation.should be_initiating_two_step_transfer_hold
315
+ end
316
+ end
317
+ end
318
+
319
+ describe "#complete_hold" do
320
+ context "given 'initiating_hold' conversation" do
321
+ before do
322
+ @conversation = create :initiating_hold_conversation
323
+ create :call, conversation: @conversation
324
+ @conversation.complete_hold!
325
+ end
326
+
327
+ it 'transitions to "in_progress_hold"' do
328
+ @conversation.should be_in_progress_hold
329
+ end
330
+ end
331
+
332
+ context "given 'initiating_two_step_transfer_hold' conversation" do
333
+ before do
334
+ @conversation = create :conversation, state: 'initiating_two_step_transfer_hold'
335
+ create :call, conversation: @conversation
336
+ @conversation.complete_hold!
337
+ end
338
+
339
+ it 'transitions to "in_progress_hold"' do
340
+ @conversation.should be_in_progress_two_step_transfer_hold
341
+ end
342
+ end
343
+ end
344
+
345
+ describe "#initiate_resume" do
346
+ context "given 'in_progress_hold' conversation" do
347
+ it "transitions to 'initiating_resume'" do
348
+ conversation = create :in_progress_hold_conversation
349
+ conversation.initiate_resume!
350
+
351
+ conversation.should be_initiating_resume
352
+ end
353
+ end
354
+
355
+ context "given 'in_progress_two_step_transfer_hold' conversation" do
356
+ it "transitions from 'in_progress_two_step_transfer_hold' to 'initiating_two_step_transfer_resume'" do
357
+ conversation = create :conversation, state: 'in_progress_two_step_transfer_hold'
358
+ conversation.initiate_resume!
359
+
360
+ conversation.should be_initiating_two_step_transfer_resume
361
+ end
362
+ end
363
+ end
364
+
365
+ describe "#complete_resume" do
366
+ context "given an 'initiating_resume' conversation" do
367
+ it "transitions from 'initiating_resume' to 'in_progress'" do
368
+ conversation = create :initiating_resume_conversation
369
+ create :call, conversation: conversation
370
+ conversation.complete_resume!
371
+
372
+ conversation.should be_in_progress
373
+ end
374
+ end
375
+
376
+ context "given an 'initiating_two_step_transfer_resume' conversation" do
377
+ it "transitions from 'initiating_two_step_transfer_resume' to 'in_progress_two_step_transfer'" do
378
+ conversation = create :conversation, state: 'initiating_two_step_transfer_resume'
379
+ create :call, conversation: conversation
380
+ conversation.complete_resume!
381
+
382
+ conversation.should be_in_progress_two_step_transfer
383
+ end
384
+ end
385
+ end
386
+ end
387
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ module Telephony
4
+ describe ConversationsPresenter do
5
+ describe '#as_json' do
6
+ before do
7
+ @conversations = 2.times.map do
8
+ conversation = create :conversation
9
+ calls = create_list :call, 2, conversation: conversation
10
+ calls.each do |call|
11
+ create :recording, call: call
12
+ end
13
+ conversation
14
+ end
15
+ conversations_presenter = ConversationsPresenter.new @conversations
16
+
17
+ @as_json = conversations_presenter.as_json
18
+ end
19
+
20
+ it 'includes each of its conversations' do
21
+ @as_json.should have(@conversations.size).conversations
22
+ end
23
+
24
+ it 'includes the calls for each of its conversations' do
25
+ @as_json.each do |conversation|
26
+ conversation[:calls].should have(2).calls
27
+ end
28
+ end
29
+
30
+ it 'includes the recordings for each of its calls for each of its conversations' do
31
+ @as_json.each do |conversation|
32
+ calls = conversation[:calls]
33
+ calls.each do |call|
34
+ call[:recordings].should have(1).recording
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,716 @@
1
+ require 'spec_helper'
2
+
3
+ module Telephony
4
+ module Events
5
+ describe Base do
6
+ describe '.log' do
7
+ let(:conversation) { create :conversation }
8
+
9
+ before do
10
+ @count = Terminate.count
11
+ @call_state = 'call_state'
12
+ @agent = create :agent
13
+ conversation.calls.create number: "1112223333",
14
+ agent: @agent
15
+
16
+ Base.log name: :terminate,
17
+ data: {
18
+ call_state: @call_state,
19
+ conversation_id: conversation.id,
20
+ call_id: conversation.calls.first.id,
21
+ conversation_state: "terminated"
22
+ }
23
+ end
24
+
25
+ it 'creates an event of the given type' do
26
+ Terminate.count.should == @count + 1
27
+ end
28
+
29
+ it 'sets its attributes from the given data' do
30
+ event = Terminate.last
31
+ event.should be
32
+ event.call_state.should == @call_state
33
+ end
34
+
35
+ it 'serializes the agent messages into message data' do
36
+ event = Terminate.last
37
+ event.message_data.should == [agent: @agent]
38
+ end
39
+ end
40
+
41
+ describe '.find_last_for_agent' do
42
+ before do
43
+ @agent = create :on_a_call_agent
44
+ end
45
+
46
+ context 'agent has no calls' do
47
+ it 'returns the default event' do
48
+ Base.find_last_for_agent(@agent).should be_an(InitializeWidget)
49
+ end
50
+ end
51
+
52
+ context 'agent has calls' do
53
+ context 'but with no events' do
54
+ before do
55
+ @conversation = create :conversation
56
+ @call = create :call, conversation: @conversation, agent: @agent
57
+ end
58
+
59
+ it 'returns the default event' do
60
+ Base.find_last_for_agent(@agent).should be_an(InitializeWidget)
61
+ end
62
+ end
63
+
64
+ context 'but with no publishable events' do
65
+ before do
66
+ @conversation = create :conversation
67
+ @call = create :call, conversation: @conversation, agent: @agent
68
+
69
+ non_publishable_event = create :answer_event, conversation: @conversation
70
+ end
71
+
72
+ it 'returns the default event' do
73
+ Base.find_last_for_agent(@agent).should be_an(InitializeWidget)
74
+ end
75
+ end
76
+
77
+ context 'with publishable events for agent2' do
78
+ before do
79
+ class Base
80
+ attr_accessible :type
81
+ end
82
+
83
+ class Dummy < Base
84
+ def publishable?
85
+ true
86
+ end
87
+
88
+ def agent_messages
89
+ [{ agent: agent2 }]
90
+ end
91
+ end
92
+ end
93
+
94
+ it 'returns the default event' do
95
+ agent1 = create :on_a_call_agent
96
+ agent2 = create :on_a_call_agent
97
+ conversation = create :conversation
98
+ agent1_call = create :call, conversation: conversation, agent: agent1
99
+ customer = create :call, conversation: conversation
100
+ agent2_call = create :call, conversation: conversation, agent: agent2
101
+ publishable_event = conversation.events.create type: 'Telephony::Events::Dummy'
102
+
103
+ Base.find_last_for_agent(agent1).should be_an(InitializeWidget)
104
+ end
105
+ end
106
+
107
+ context 'with publishable events for agent1' do
108
+ before do
109
+ @agent1 = create :on_a_call_agent
110
+ @conversation1 = create :conversation
111
+ create :call, conversation: @conversation1, agent: @agent1
112
+ create :call, conversation: @conversation1
113
+ publishable_event = build :conversation_start_event, conversation: @conversation1
114
+
115
+ publishable_event.update_attributes message_data: publishable_event.agent_messages
116
+ end
117
+
118
+ it 'returns the last event for agent1' do
119
+ Base.find_last_for_agent(@agent1).should be_an(Start)
120
+ end
121
+
122
+ context "even if another agent transfers a call to the first agent" do
123
+ before do
124
+ @conversation2 = create(:in_progress_conversation).tap do |conversation|
125
+ create :active_agent_leg, conversation: @conversation2
126
+ create :customer_leg, conversation: @conversation2
127
+ end
128
+ @conversation2.transfer!(@agent1.csr_id, true)
129
+ end
130
+
131
+ it 'still returns the last event for agent1' do
132
+ Base.find_last_for_agent(@agent1).should be_an(Start)
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ context "given an agent that's not on a call" do
139
+ before do
140
+ @agent = create :available_agent
141
+
142
+ @event = Base.find_last_for_agent @agent
143
+ end
144
+
145
+ it 'returns a new default event' do
146
+ @event.should be_an(InitializeWidget)
147
+ end
148
+ end
149
+ end
150
+
151
+ describe '#new_default_event' do
152
+ before do
153
+ @event = Base.new_default_event
154
+ end
155
+
156
+ it 'returns a new initialize widget event' do
157
+ @event.should be_an(InitializeWidget)
158
+ end
159
+ end
160
+
161
+ describe '#publish' do
162
+ let(:event_publisher) { mock(:event_publisher) }
163
+
164
+ context "given a publishable event" do
165
+ let(:event) { build(:publishable_event) }
166
+
167
+ context "with an agent" do
168
+ before do
169
+ event.message_data = event.agent_messages
170
+ PusherEventPublisher
171
+ .should_receive(:publish)
172
+ .with(channel: "csrs-#{event.call.agent.csr_id}",
173
+ name: event.class.name.demodulize,
174
+ data: {
175
+ event_id: event.id,
176
+ conversation_id: event.conversation.id,
177
+ conversation_state: event.conversation.state,
178
+ call_id: event.call.id,
179
+ number: event.conversation.customer.number,
180
+ loan_id: event.conversation.loan_id,
181
+ owner: true
182
+ })
183
+ end
184
+
185
+ it "asks the event publisher to publish an event" do
186
+ event.publish
187
+ end
188
+ end
189
+
190
+ context "with no agent" do
191
+ before do
192
+ event.call.stub(:agent).and_return nil
193
+ PusherEventPublisher.should_not_receive(:publish)
194
+ end
195
+
196
+ it "does not ask the event publisher to publish an event" do
197
+ event.publish
198
+ end
199
+ end
200
+ end
201
+
202
+ context 'given a non-publishable event' do
203
+ let(:event) { build(:non_publishable_event) }
204
+
205
+ before do
206
+ PusherEventPublisher.should_not_receive(:publish)
207
+ end
208
+
209
+ it "does not ask the event publisher to publish an event" do
210
+ event.publish
211
+ end
212
+ end
213
+ end
214
+
215
+ describe '#publishable?' do
216
+ context 'by default' do
217
+ before do
218
+ @event = Base.new
219
+ end
220
+
221
+ it 'returns false' do
222
+ @event.should_not be_publishable
223
+ end
224
+ end
225
+ end
226
+
227
+ describe '#default_data' do
228
+ let(:event) { create(:publishable_event) }
229
+
230
+ it 'returns the event data' do
231
+ event.default_data[:event_id].should == event.id
232
+ event.default_data[:conversation_id].should == event.conversation.id
233
+ event.default_data[:conversation_state].should == event.conversation.state
234
+ event.default_data[:call_id].should == event.call.id
235
+ event.default_data[:number].should == event.conversation.customer.number
236
+ event.default_data[:loan_id].should == event.conversation.loan_id
237
+ event.default_data[:owner].should == true
238
+ end
239
+ end
240
+
241
+ describe "#agent2" do
242
+ it "returns the last call's agent" do
243
+ agent1 = create :agent
244
+ agent2 = create :agent
245
+ conversation = create :conversation
246
+ agent1_call = create :call, conversation: conversation, agent: agent1
247
+ customer = create :call, conversation: conversation
248
+ agent2_call = create :call, conversation: conversation, agent: agent2, state: 'terminated'
249
+ event = create(:two_step_transfer_failed_event, conversation: conversation)
250
+
251
+ event.send(:agent2).should == agent2
252
+ end
253
+ end
254
+
255
+ describe '#republish_only_for' do
256
+ context 'given an event that was published for multiple agents' do
257
+ before do
258
+ @event = create :two_step_transfer_failed_event
259
+ end
260
+
261
+ context 'and the current agent received the event' do
262
+ before do
263
+ @agent = @event.agent2
264
+ PusherEventPublisher.should_receive :publish
265
+ end
266
+
267
+ it 'republishes the event for the current agent' do
268
+ @event.republish_only_for @agent
269
+ end
270
+ end
271
+
272
+ context 'and the current agent did not receive the event' do
273
+ before do
274
+ @agent = create :agent
275
+ PusherEventPublisher.should_not_receive :publish
276
+ end
277
+
278
+ it 'does not republish the event for the current agent' do
279
+ @event.republish_only_for @agent
280
+ end
281
+ end
282
+ end
283
+ end
284
+ end
285
+
286
+ describe Connect do
287
+ describe '#agent_messages' do
288
+ context "for agent1" do
289
+ let(:event) { build(:agent_call_connect_event) }
290
+
291
+ before do
292
+ @agent1 = event.agent_messages.first[:agent]
293
+ end
294
+
295
+ it 'returns agent1' do
296
+ @agent1.should == event.conversation.first_active_agent
297
+ end
298
+
299
+ it 'sets owner to true' do
300
+ event.agent_messages.first[:data][:owner].should be_true
301
+ end
302
+ end
303
+
304
+ context "for agent2" do
305
+ let(:event) { build :agent_call_connect_event }
306
+
307
+ before do
308
+ event.should_receive(:agent1).and_return('something not equal')
309
+ end
310
+
311
+ it 'sets owner to false' do
312
+ event.agent_messages.first[:data][:owner].should be_false
313
+ end
314
+ end
315
+ end
316
+
317
+ describe '#publishable?' do
318
+ context 'given a call connect event' do
319
+ context 'for an agent' do
320
+ let(:event) { build(:agent_call_connect_event) }
321
+
322
+ it 'returns true' do
323
+ event.should be_publishable
324
+ end
325
+ end
326
+
327
+ context 'for a non agent' do
328
+ let(:event) { build(:borrower_call_connect_event) }
329
+
330
+ it 'returns false' do
331
+ event.should_not be_publishable
332
+ end
333
+ end
334
+
335
+ context 'for a transferring conversation' do
336
+ let(:event) { build(:agent_call_connect_event,
337
+ conversation_state: 'one_step_transferring') }
338
+
339
+ it 'returns false' do
340
+ event.should_not be_publishable
341
+ end
342
+ end
343
+ end
344
+
345
+ context 'given a conversation connect event' do
346
+ let(:event) { build(:conversation_connect_event) }
347
+
348
+ it 'returns false' do
349
+ event.should_not be_publishable
350
+ end
351
+ end
352
+ end
353
+ end
354
+
355
+ describe Start do
356
+ describe '#agent_messages' do
357
+ let(:event) { build :conversation_start_event }
358
+
359
+ before do
360
+ @agent1 = event.agent_messages.first[:agent]
361
+ end
362
+
363
+ it 'returns agent1' do
364
+ @agent1.should == event.conversation.first_active_agent
365
+ end
366
+ end
367
+
368
+ describe '#publishable?' do
369
+ let(:event) { build(:conversation_start_event) }
370
+
371
+ it 'returns true' do
372
+ event.should be_publishable
373
+ end
374
+ end
375
+ end
376
+
377
+ describe CallAnswered do
378
+ context "for an agent's call" do
379
+ describe '#agent_messages' do
380
+ context "for agent1" do
381
+ let(:event) { build :conversation_answer_event }
382
+
383
+ before do
384
+ @agent1 = event.agent_messages.first[:agent]
385
+ end
386
+
387
+ it 'returns agent1' do
388
+ @agent1.should == event.conversation.first_active_agent
389
+ end
390
+
391
+ it 'sets owner to true' do
392
+ event.agent_messages.first[:data][:owner].should be_true
393
+ end
394
+ end
395
+
396
+ context "for agent2" do
397
+ let(:event) { build :conversation_answer_event }
398
+
399
+ before do
400
+ event.should_receive(:agent1).and_return('something not equal')
401
+ end
402
+
403
+ it 'sets owner to false' do
404
+ event.agent_messages.first[:data][:owner].should be_false
405
+ end
406
+ end
407
+ end
408
+
409
+ describe '#publishable?' do
410
+ let(:event) { build(:conversation_answer_event) }
411
+
412
+ it 'returns true' do
413
+ event.should be_publishable
414
+ end
415
+ end
416
+ end
417
+
418
+ context "for a customer's call" do
419
+ describe '#publishable?' do
420
+ let(:event) { build(:conversation_answer_event_for_customer) }
421
+
422
+ it 'returns false' do
423
+ event.should_not be_publishable
424
+ end
425
+ end
426
+ end
427
+ end
428
+
429
+ describe Ended do
430
+ describe '#agent_messages' do
431
+ let(:event) { build(:csr_call_ended_event) }
432
+
433
+ before do
434
+ @agent = event.agent_messages.first[:agent]
435
+ end
436
+
437
+ it "returns the call's agent" do
438
+ @agent.should == event.call.agent
439
+ end
440
+ end
441
+
442
+ describe '#publishable?' do
443
+ context 'given a call ended event' do
444
+ context 'for a CSR' do
445
+ let(:event) { build(:csr_call_ended_event) }
446
+
447
+ it 'returns true' do
448
+ event.should be_publishable
449
+ end
450
+ end
451
+
452
+ context 'for a non CSR' do
453
+ let(:event) { build(:borrower_call_ended_event) }
454
+
455
+ it 'returns false' do
456
+ event.should_not be_publishable
457
+ end
458
+ end
459
+ end
460
+
461
+ context 'given a conversation ended event' do
462
+ let(:event) { build(:conversation_ended_event) }
463
+
464
+ it 'returns false' do
465
+ event.should_not be_publishable
466
+ end
467
+ end
468
+ end
469
+ end
470
+
471
+ describe Transfer do
472
+ describe '#publishable?' do
473
+ let(:event) { build(:two_step_transfer_initiated_event) }
474
+
475
+ it 'returns true' do
476
+ event.should be_publishable
477
+ end
478
+ end
479
+
480
+ describe '#agent_messages' do
481
+ let(:event) { build(:two_step_transfer_initiated_event) }
482
+
483
+ context 'for agent1' do
484
+ before do
485
+ @agent1 = event.agent_messages.first[:agent]
486
+ @agent1_data = event.agent_messages.first[:data]
487
+ end
488
+
489
+ it 'returns agent1' do
490
+ @agent1 == event.conversation.first_active_agent
491
+ end
492
+
493
+ it 'returns the event data' do
494
+ @agent1_data[:transferrer].should be_true
495
+ @agent1_data[:agent_name].should == event.conversation.second_active_agent.name
496
+ @agent1_data[:agent_ext].should == event.conversation.second_active_agent.phone_ext
497
+ @agent1_data[:agent_type].should == event.conversation.second_active_agent.csr_type
498
+ end
499
+ end
500
+
501
+ context 'for agent2' do
502
+ before do
503
+ @agent2 = event.agent_messages.last[:agent]
504
+ @agent2_data = event.agent_messages.last[:data]
505
+ end
506
+
507
+ it 'returns agent2' do
508
+ @agent2.should == event.conversation.second_active_agent
509
+ end
510
+
511
+ it 'returns the event data' do
512
+ @agent2_data[:transferrer].should be_false
513
+ @agent2_data[:agent_name].should == event.conversation.first_active_agent.name
514
+ @agent2_data[:agent_ext].should == event.conversation.first_active_agent.phone_ext
515
+ @agent2_data[:agent_type].should == event.conversation.first_active_agent.csr_type
516
+ @agent2_data[:owner].should == false
517
+ end
518
+ end
519
+ end
520
+ end
521
+
522
+ describe LeaveTwoStepTransfer do
523
+ describe '#publishable?' do
524
+ let(:event) { build(:leave_two_step_transfer_event) }
525
+
526
+ it 'returns true' do
527
+ event.should be_publishable
528
+ end
529
+ end
530
+
531
+ describe '#agent_messages' do
532
+ let(:event) { build(:leave_two_step_transfer_event) }
533
+
534
+ before do
535
+ @agent = event.agent_messages.first[:agent]
536
+ end
537
+
538
+ it 'returns agent1' do
539
+ @agent.should == event.conversation.first_active_agent
540
+ end
541
+ end
542
+ end
543
+
544
+ describe FailOneStepTransfer do
545
+ let(:event) { build(:one_step_transfer_failed_event) }
546
+
547
+ describe '#publishable?' do
548
+ it 'returns true' do
549
+ event.should be_publishable
550
+ end
551
+ end
552
+
553
+ describe '#agent_messages' do
554
+ context 'for agent1' do
555
+ before do
556
+ @agent1 = event.agent_messages.first[:agent]
557
+ @agent1_data = event.agent_messages.first[:data]
558
+ end
559
+
560
+ it 'returns agent1' do
561
+ @agent1.should == event.conversation.first_inactive_agent
562
+ end
563
+
564
+ it 'returns the event data' do
565
+ @agent1_data[:transferrer].should be_true
566
+ @agent1_data[:agent_name].should == event.conversation.transferee.name
567
+ @agent1_data[:agent_ext].should == event.conversation.transferee.phone_ext
568
+ @agent1_data[:agent_type].should == event.conversation.transferee.csr_type
569
+ end
570
+ end
571
+
572
+ end
573
+
574
+ describe '#agent1' do
575
+ before do
576
+ @agent1 = event.agent1
577
+ end
578
+
579
+ it "returns its conversation's first inactive agent" do
580
+ @agent1.should == event.conversation.first_inactive_agent
581
+ end
582
+ end
583
+ end
584
+
585
+ describe LeaveVoicemail do
586
+ describe '#publishable?' do
587
+ let(:event) { build :leave_voicemail_event }
588
+
589
+ it 'returns true' do
590
+ event.should be_publishable
591
+ end
592
+ end
593
+
594
+ describe '#agent_messages' do
595
+ let(:event) { build :leave_voicemail_event }
596
+
597
+ before do
598
+ @agent_messages = event.agent_messages.first
599
+ end
600
+
601
+ it 'returns agent1' do
602
+ @agent_messages[:agent].should == event.agent1
603
+ end
604
+
605
+ it 'returns agent2 data' do
606
+ agent2 = event.agent2
607
+ data = @agent_messages[:data]
608
+ data[:agent_name].should == agent2.name
609
+ data[:agent_ext].should == agent2.phone_ext
610
+ data[:agent_type].should == agent2.csr_type
611
+ end
612
+ end
613
+ end
614
+
615
+ describe CompleteHold do
616
+ context "conversation level event" do
617
+ let(:event) { build :complete_hold_event }
618
+
619
+ describe "#publishable?" do
620
+ it { event.should be_publishable }
621
+ end
622
+
623
+ describe "#agent_messages" do
624
+ context "when there is one agent" do
625
+ it "publishes to first agent's channel" do
626
+ first_agent = event.agent_messages.first[:agent]
627
+ first_agent.should == event.agent1
628
+ end
629
+
630
+ it "does not publish for agent2" do
631
+ event.agent_messages.size.should == 1
632
+ end
633
+ end
634
+
635
+ context "when there are two agents" do
636
+ before do
637
+ @agent2_leg = build :active_agent_leg
638
+ event.conversation.calls.concat([@agent2_leg])
639
+ @agent2_msgs = event.agent_messages.last
640
+ end
641
+
642
+ it "publishes to second agent's channel" do
643
+ second_agent = @agent2_msgs[:agent]
644
+ second_agent.should == @agent2_leg.agent
645
+ end
646
+
647
+ it "sets owner to false" do
648
+ @agent2_msgs[:data][:owner].should == false
649
+ end
650
+ end
651
+ end
652
+ end
653
+
654
+ context "call level event" do
655
+ let(:event) { build :complete_hold_event, call_id: 1 }
656
+
657
+ describe "#publishable?" do
658
+ it { event.should_not be_publishable }
659
+ end
660
+ end
661
+ end
662
+
663
+ describe CompleteResume do
664
+ let(:event) { build :complete_resume_event }
665
+
666
+ describe "#publishable?" do
667
+ it { event.should be_publishable }
668
+ end
669
+
670
+ describe "#agent_messages" do
671
+ context "when there is one agent" do
672
+ it "publishes to first agent's channel" do
673
+ first_agent = event.agent_messages.first[:agent]
674
+ first_agent.should == event.agent1
675
+ end
676
+
677
+ it "does not publish for agent2" do
678
+ event.agent_messages.size.should == 1
679
+ end
680
+ end
681
+
682
+ context "when there are two agents" do
683
+ before do
684
+ @agent2_leg = build :active_agent_leg
685
+ event.conversation.calls.concat([@agent2_leg])
686
+ @agent2_msgs = event.agent_messages.last
687
+ end
688
+
689
+ it "publishes to second agent's channel" do
690
+ second_agent = @agent2_msgs[:agent]
691
+ second_agent.should == @agent2_leg.agent
692
+ end
693
+
694
+ it "sets owner to false" do
695
+ @agent2_msgs[:data][:owner].should == false
696
+ end
697
+ end
698
+ end
699
+ end
700
+
701
+ describe InitializeWidget do
702
+ describe '#republish_only_for' do
703
+ before do
704
+ @agent = create :agent
705
+ @event = InitializeWidget.new
706
+
707
+ PusherEventPublisher.should_receive :publish
708
+ end
709
+
710
+ it 'republishes the event for the current agent' do
711
+ @event.republish_only_for @agent
712
+ end
713
+ end
714
+ end
715
+ end
716
+ end