chat.rb 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
  2. class Chat < ApplicationModel
  3. validates :name, presence: true
  4. store :preferences
  5. def customer_state(session_id = nil)
  6. return { state: 'chat_disabled' } if !Setting.get('chat')
  7. # reconnect
  8. if session_id
  9. chat_session = Chat::Session.find_by(session_id: session_id, state: %w[waiting running])
  10. if chat_session
  11. if chat_session.state == 'running'
  12. user = nil
  13. if chat_session.user_id
  14. chat_user = User.lookup(id: chat_session.user_id)
  15. url = nil
  16. if chat_user.image && chat_user.image != 'none'
  17. url = "#{Setting.get('http_type')}://#{Setting.get('fqdn')}/api/v1/users/image/#{chat_user.image}"
  18. end
  19. user = {
  20. name: chat_user.fullname,
  21. avatar: url,
  22. }
  23. # get queue postion if needed
  24. session = Chat::Session.messages_by_session_id(session_id)
  25. if session
  26. return {
  27. state: 'reconnect',
  28. session: session,
  29. agent: user,
  30. }
  31. end
  32. end
  33. elsif chat_session.state == 'waiting'
  34. return {
  35. state: 'reconnect',
  36. position: chat_session.position,
  37. }
  38. end
  39. end
  40. end
  41. # check if agents are available
  42. available_agents = Chat::Agent.where(active: true).where('updated_at > ?', Time.zone.now - 2.minutes).count
  43. if available_agents.zero?
  44. return { state: 'offline' }
  45. end
  46. # if all seads are used
  47. if Chat.waiting_chat_count >= max_queue
  48. return {
  49. state: 'no_seats_available',
  50. queue: Chat.waiting_chat_count,
  51. }
  52. end
  53. # seads are available
  54. { state: 'online' }
  55. end
  56. def self.agent_state(user_id)
  57. return { state: 'chat_disabled' } if !Setting.get('chat')
  58. assets = {}
  59. Chat.where(active: true).each do |chat|
  60. assets = chat.assets(assets)
  61. end
  62. active_agent_ids = []
  63. active_agents.each do |user|
  64. active_agent_ids.push user.id
  65. assets = user.assets(assets)
  66. end
  67. runningchat_session_list_local = running_chat_session_list
  68. runningchat_session_list_local.each do |session|
  69. next if !session['user_id']
  70. user = User.lookup(id: session['user_id'])
  71. next if !user
  72. assets = user.assets(assets)
  73. end
  74. {
  75. waiting_chat_count: waiting_chat_count,
  76. waiting_chat_session_list: waiting_chat_session_list,
  77. running_chat_count: running_chat_count,
  78. running_chat_session_list: runningchat_session_list_local,
  79. active_agent_count: active_agent_count,
  80. active_agent_ids: active_agent_ids,
  81. seads_available: seads_available,
  82. seads_total: seads_total,
  83. active: Chat::Agent.state(user_id),
  84. assets: assets,
  85. }
  86. end
  87. def self.agent_state_with_sessions(user_id)
  88. return { state: 'chat_disabled' } if !Setting.get('chat')
  89. result = agent_state(user_id)
  90. result[:active_sessions] = Chat::Session.active_chats_by_user_id(user_id)
  91. result
  92. end
  93. def self.waiting_chat_count
  94. Chat::Session.where(state: ['waiting']).count
  95. end
  96. def self.waiting_chat_session_list
  97. sessions = []
  98. Chat::Session.where(state: ['waiting']).each do |session|
  99. sessions.push session.attributes
  100. end
  101. sessions
  102. end
  103. def self.running_chat_count
  104. Chat::Session.where(state: ['running']).count
  105. end
  106. def self.running_chat_session_list
  107. sessions = []
  108. Chat::Session.where(state: ['running']).each do |session|
  109. sessions.push session.attributes
  110. end
  111. sessions
  112. end
  113. def self.active_chat_count
  114. Chat::Session.where(state: %w[waiting running]).count
  115. end
  116. def self.available_agents(diff = 2.minutes)
  117. agents = {}
  118. Chat::Agent.where(active: true).where('updated_at > ?', Time.zone.now - diff).each do |record|
  119. agents[record.updated_by_id] = record.concurrent
  120. end
  121. agents
  122. end
  123. def self.active_agent_count(diff = 2.minutes)
  124. Chat::Agent.where(active: true).where('updated_at > ?', Time.zone.now - diff).count
  125. end
  126. def self.active_agents(diff = 2.minutes)
  127. users = []
  128. Chat::Agent.where(active: true).where('updated_at > ?', Time.zone.now - diff).each do |record|
  129. user = User.lookup(id: record.updated_by_id)
  130. next if !user
  131. users.push user
  132. end
  133. users
  134. end
  135. def self.seads_total(diff = 2.minutes)
  136. total = 0
  137. available_agents(diff).each_value do |concurrent|
  138. total += concurrent
  139. end
  140. total
  141. end
  142. def self.seads_available(diff = 2.minutes)
  143. seads_total(diff) - active_chat_count
  144. end
  145. =begin
  146. broadcast new agent status to all agents
  147. Chat.broadcast_agent_state_update
  148. optional you can ignore it for dedecated user
  149. Chat.broadcast_agent_state_update(ignore_user_id)
  150. =end
  151. def self.broadcast_agent_state_update(ignore_user_id = nil)
  152. # send broadcast to agents
  153. Chat::Agent.where('active = ? OR updated_at > ?', true, Time.zone.now - 8.hours).each do |item|
  154. next if item.updated_by_id == ignore_user_id
  155. data = {
  156. event: 'chat_status_agent',
  157. data: Chat.agent_state(item.updated_by_id),
  158. }
  159. Sessions.send_to(item.updated_by_id, data)
  160. end
  161. end
  162. =begin
  163. broadcast new customer queue position to all waiting customers
  164. Chat.broadcast_customer_state_update
  165. =end
  166. def self.broadcast_customer_state_update
  167. # send position update to other waiting sessions
  168. position = 0
  169. Chat::Session.where(state: 'waiting').order('created_at ASC').each do |local_chat_session|
  170. position += 1
  171. data = {
  172. event: 'chat_session_queue',
  173. data: {
  174. state: 'queue',
  175. position: position,
  176. session_id: local_chat_session.session_id,
  177. },
  178. }
  179. local_chat_session.send_to_recipients(data)
  180. end
  181. end
  182. =begin
  183. cleanup old chat messages
  184. Chat.cleanup
  185. optional you can put the max oldest chat entries
  186. Chat.cleanup(3.months)
  187. =end
  188. def self.cleanup(diff = 3.months)
  189. Chat::Session.where(state: 'closed').where('updated_at < ?', Time.zone.now - diff).each do |chat_session|
  190. Chat::Message.where(chat_session_id: chat_session.id).delete_all
  191. chat_session.destroy
  192. end
  193. true
  194. end
  195. =begin
  196. close chat sessions where participients are offline
  197. Chat.cleanup_close
  198. optional you can put the max oldest chat sessions as argument
  199. Chat.cleanup_close(5.minutes)
  200. =end
  201. def self.cleanup_close(diff = 5.minutes)
  202. Chat::Session.where.not(state: 'closed').where('updated_at < ?', Time.zone.now - diff).each do |chat_session|
  203. next if chat_session.recipients_active?
  204. chat_session.state = 'closed'
  205. chat_session.save
  206. message = {
  207. event: 'chat_session_closed',
  208. data: {
  209. session_id: chat_session.session_id,
  210. realname: 'System',
  211. },
  212. }
  213. chat_session.send_to_recipients(message)
  214. end
  215. true
  216. end
  217. =begin
  218. check if ip address is blocked for chat
  219. chat = Chat.find(123)
  220. chat.blocked_ip?(ip)
  221. =end
  222. def blocked_ip?(ip)
  223. return false if ip.blank?
  224. return false if block_ip.blank?
  225. ips = block_ip.split(';')
  226. ips.each do |local_ip|
  227. return true if ip == local_ip.strip
  228. return true if ip.match?(/#{local_ip.strip.gsub(/\*/, '.+?')}/)
  229. end
  230. false
  231. end
  232. =begin
  233. check if country is blocked for chat
  234. chat = Chat.find(123)
  235. chat.blocked_country?(ip)
  236. =end
  237. def blocked_country?(ip)
  238. return false if ip.blank?
  239. return false if block_country.blank?
  240. geo_ip = Service::GeoIp.location(ip)
  241. return false if geo_ip.blank?
  242. return false if geo_ip['country_code'].blank?
  243. countries = block_country.split(';')
  244. countries.each do |local_country|
  245. return true if geo_ip['country_code'] == local_country
  246. end
  247. false
  248. end
  249. end