From 39b37e048b5bdaeb2ec65fa6e79381e66a18f2ef Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Wed, 25 Nov 2015 10:33:39 +0100 Subject: [PATCH] Added chat settings. Improved chat event backends. --- .../javascripts/app/controllers/chat.coffee | 115 ++++++++++++++++-- app/assets/javascripts/app/models/chat.coffee | 4 +- .../app/views/channel/chat.jst.eco | 16 +-- .../app/views/customer_chat/index.jst.eco | 2 +- .../app/views/customer_chat/setting.jst.eco | 34 ++++++ app/controllers/users_controller.rb | 5 +- app/models/chat.rb | 11 +- lib/sessions/event/chat_agent_state.rb | 14 +-- lib/sessions/event/chat_base.rb | 88 ++++++++++++++ lib/sessions/event/chat_session_close.rb | 20 +-- lib/sessions/event/chat_session_init.rb | 14 +-- lib/sessions/event/chat_session_message.rb | 21 +--- lib/sessions/event/chat_session_start.rb | 2 + lib/sessions/event/chat_session_typing.rb | 21 +--- lib/sessions/event/chat_status_agent.rb | 1 + lib/sessions/event/chat_status_customer.rb | 14 +-- 16 files changed, 262 insertions(+), 120 deletions(-) create mode 100644 app/assets/javascripts/app/views/customer_chat/setting.jst.eco diff --git a/app/assets/javascripts/app/controllers/chat.coffee b/app/assets/javascripts/app/controllers/chat.coffee index b9db911ef..d61525233 100644 --- a/app/assets/javascripts/app/controllers/chat.coffee +++ b/app/assets/javascripts/app/controllers/chat.coffee @@ -3,6 +3,7 @@ class App.CustomerChat extends App.Controller events: 'click .js-acceptChat': 'acceptChat' + 'click .js-settings': 'settings' sounds: chat_new: new Audio('assets/sounds/chat_new.mp3') @@ -19,7 +20,11 @@ class App.CustomerChat extends App.Controller return @chatWindows = {} - @maxChats = 4 + @maxChatWindows = 4 + preferences = @Session.get('preferences') + if preferences && preferences.chat && preferences.chat.max_windows + @maxChatWindows = parseInt(preferences.chat.max_windows) + @pushStateStarted = false @messageCounter = 0 @meta = @@ -33,6 +38,8 @@ class App.CustomerChat extends App.Controller # update navbar on new status @bind('chat_status_agent', (data) => + if data.assets + App.Collection.loadAssets(data.assets) @meta = data @updateMeta() if !@pushStateStarted @@ -42,6 +49,7 @@ class App.CustomerChat extends App.Controller # add new chat window @bind('chat_session_start', (data) => + console.log('chat_session_start', data) if data.session @addChat(data.session) ) @@ -103,6 +111,16 @@ class App.CustomerChat extends App.Controller if state is undefined return @meta.active + # check if min one chat is active + if state + preferences = @Session.get('preferences') + if !preferences || !preferences.chat || !preferences.chat.active || _.isEmpty(preferences.chat.active) + @notify( + type: 'error' + msg: App.i18n.translateContent('To be able to chat you need to select min. one chat topic in settings!') + ) + return + @meta.active = state # write state @@ -118,7 +136,7 @@ class App.CustomerChat extends App.Controller @delay(delay, 200, 'updateNavMenu') updateMeta: => - if @meta.waiting_chat_count && @maxChats > @windowCount() + if @meta.waiting_chat_count && @maxChatWindows > @windowCount() @$('.js-acceptChat').addClass('is-clickable is-blinking') else @$('.js-acceptChat').removeClass('is-clickable is-blinking') @@ -130,6 +148,7 @@ class App.CustomerChat extends App.Controller if @meta.active_sessions for session in @meta.active_sessions @addChat(session) + console.log('updateMeta aC', session) @meta.active_sessions = false @updateNavMenu() @@ -165,9 +184,14 @@ class App.CustomerChat extends App.Controller chat.trigger 'layout-changed' acceptChat: => - return if @windowCount() >= @maxChats + return if @windowCount() >= @maxChatWindows App.WebSocket.send(event:'chat_session_start') + settings: -> + new Setting( + maxChatWindows: @maxChatWindows + ) + class CustomerChatRouter extends App.ControllerPermanent constructor: (params) -> super @@ -243,12 +267,21 @@ class ChatWindow extends App.Controller @el.addClass('is-open') # @addMessage 'Hello. My name is Roger, how can I help you?', 'agent' - if @session && @session.messages - for message in @session.messages - if message.created_by_id - @addMessage message.content, 'agent' - else - @addMessage message.content, 'customer' + if @session + if @session.messages + for message in @session.messages + if message.created_by_id + @addMessage message.content, 'agent' + else + @addMessage message.content, 'customer' + + # send init reply + if !@session.messages || _.isEmpty(@session.messages) + preferences = @Session.get('preferences') + if preferences.chat && preferences.chat.phrase + phrases = preferences.chat.phrase[@session.chat_id] + if phrases + @sendMessage phrases focus: => @input.focus() @@ -319,11 +352,12 @@ class ChatWindow extends App.Controller event.preventDefault() @sendMessage() - sendMessage: => - content = @input.html() + sendMessage: (content) => + if !content + content = @input.html() return if !content - #@trigger "answer", @input.html() + console.log('send', content, @session.session_id) App.WebSocket.send( event:'chat_session_message' data: @@ -431,6 +465,63 @@ class ChatWindow extends App.Controller scrollToBottom: -> @scrollHolder.scrollTop(@scrollHolder.prop('scrollHeight')) +class Setting extends App.ControllerModalNice + buttonClose: true + buttonCancel: true + buttonSubmit: true + head: 'Settings' + + content: => + + preferences = @Session.get('preferences') + if !preferences + preferences = {} + if !preferences.chat + preferences.chat = {} + if !preferences.chat.active + preferences.chat.active = {} + if !preferences.chat.phrase + preferences.chat.phrase = {} + if !preferences.chat.max_windows + preferences.chat.max_windows = @maxChatWindows + + App.view('customer_chat/setting')( + chats: App.Chat.all() + preferences: preferences + ) + + submit: (e) => + e.preventDefault() + params = @formParam(e.target) + + @formDisable(e) + + # get data + @ajax( + id: 'preferences' + type: 'PUT' + url: "#{@apiPath}/users/preferences" + data: JSON.stringify({user:params}) + processData: true + success: @success + error: @error + ) + + success: (data, status, xhr) => + App.User.full( + App.Session.get('id'), + => + @close() + , + true + ) + + error: (xhr, status, error) => + data = JSON.parse(xhr.responseText) + @notify( + type: 'error' + msg: App.i18n.translateContent(data.message) + ) App.Config.set( 'customer_chat', CustomerChatRouter, 'Routes' ) App.Config.set( 'CustomerChat', { controller: 'CustomerChat', authentication: true }, 'permanentTask' ) diff --git a/app/assets/javascripts/app/models/chat.coffee b/app/assets/javascripts/app/models/chat.coffee index b80361ce0..4a93284bb 100644 --- a/app/assets/javascripts/app/models/chat.coffee +++ b/app/assets/javascripts/app/models/chat.coffee @@ -6,8 +6,8 @@ class App.Chat extends App.Model @configure_attributes = [ { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false }, { name: 'note', display: 'Note', tag: 'textarea', limit: 250, null: true }, - { name: 'public', display: 'Public', tag: 'boolean', default: true }, - { name: 'max_queue', display: 'Max. Queue', tag: 'input', default: 5 }, + #{ name: 'public', display: 'Public', tag: 'boolean', default: true }, + { name: 'max_queue', display: 'Max. clients in waitlist', tag: 'input', default: 2 }, { name: 'active', display: 'Active', tag: 'active', default: true }, { name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 }, { name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 }, diff --git a/app/assets/javascripts/app/views/channel/chat.jst.eco b/app/assets/javascripts/app/views/channel/chat.jst.eco index 06c78c7ee..8081932e9 100644 --- a/app/assets/javascripts/app/views/channel/chat.jst.eco +++ b/app/assets/javascripts/app/views/channel/chat.jst.eco @@ -1,19 +1,19 @@

<%- @T('You can create chat widgets for your webpages to allow visitors to chat with you.') %>

-

<%- @T('Channels') %>

-

<%- @T('You can create multiple chat channels.') %>

+

<%- @T('Topics') %>

+

<%- @T('You can create multiple chat topics.') %>

- + @@ -41,7 +41,7 @@ <% end %>
<%- @T('Name') %> <%- @T('Note') %><%- @T('Max Queue') %><%- @T('Max. clients in waitlist') %> <%- @T('Delete') %>
- <%- @Icon('plus-small') %> Add Channel + <%- @Icon('plus-small') %> <%- @T('Add') %>
@@ -57,7 +57,7 @@
- +
@@ -149,7 +149,7 @@
-
+
@@ -222,7 +222,7 @@ $(function() { <%- marked(@T('When you turn on debugging by setting the option `debug` to `true` the reason gets printed to the javascript console.')) %>

- +

<%- @T('Options') %>

diff --git a/app/assets/javascripts/app/views/customer_chat/index.jst.eco b/app/assets/javascripts/app/views/customer_chat/index.jst.eco index 894a4c92f..ec09e5379 100644 --- a/app/assets/javascripts/app/views/customer_chat/index.jst.eco +++ b/app/assets/javascripts/app/views/customer_chat/index.jst.eco @@ -17,7 +17,7 @@
-
<%- @T('Settings') %>
+
<%- @T('Settings') %>
diff --git a/app/assets/javascripts/app/views/customer_chat/setting.jst.eco b/app/assets/javascripts/app/views/customer_chat/setting.jst.eco new file mode 100644 index 000000000..396e42e01 --- /dev/null +++ b/app/assets/javascripts/app/views/customer_chat/setting.jst.eco @@ -0,0 +1,34 @@ +
+ + + + +<% for chat in @chats: %> + + + +
+ +
+ + <%- @Icon('arrow-down', 'dropdown-arrow') %> +
+
+ +
<%- @T('Topic') %> + <%- @T('Greeting') %> + <%- @T('Enabled') %> +
<%= chat.name %> + + + +<% end %> +
\ No newline at end of file diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 9a7cb331a..dd0ac8d9d 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -572,10 +572,11 @@ curl http://localhost/api/v1/users/preferences.json -v -u #{login}:#{password} - return end if params[:user] + user = User.find(current_user.id) params[:user].each {|key, value| - current_user.preferences[key.to_sym] = value + user.preferences[key.to_sym] = value } - current_user.save + user.save end render json: { message: 'ok' }, status: :ok end diff --git a/app/models/chat.rb b/app/models/chat.rb index 356da3aa0..2a013e880 100644 --- a/app/models/chat.rb +++ b/app/models/chat.rb @@ -51,10 +51,10 @@ class Chat < ApplicationModel end # if all seads are used - if Chat.active_chat_count >= max_queue + if Chat.waiting_chat_count >= max_queue return { state: 'no_seats_available', - queue: Chat.seads_available, + queue: Chat.waiting_chat_count, } end @@ -64,6 +64,10 @@ class Chat < ApplicationModel def self.agent_state(user_id) return { state: 'chat_disabled' } if !Setting.get('chat') + assets = {} + Chat.where(active: true).each {|chat| + assets = chat.assets(assets) + } { waiting_chat_count: waiting_chat_count, running_chat_count: running_chat_count, @@ -71,7 +75,8 @@ class Chat < ApplicationModel active_agents: active_agents, seads_available: seads_available, seads_total: seads_total, - active: Chat::Agent.state(user_id) + active: Chat::Agent.state(user_id), + assets: assets, } end diff --git a/lib/sessions/event/chat_agent_state.rb b/lib/sessions/event/chat_agent_state.rb index 4edc40b61..f89a517bc 100644 --- a/lib/sessions/event/chat_agent_state.rb +++ b/lib/sessions/event/chat_agent_state.rb @@ -2,18 +2,8 @@ class Sessions::Event::ChatAgentState < Sessions::Event::ChatBase def run - # only agents can do this - chat_id = 1 - chat = Chat.find_by(id: chat_id) - if !@session['id'] - return { - event: 'chat_agent_state', - data: { - state: 'failed', - message: 'No such user_id.' - }, - } - end + # check if user has permissions + return if !agent_permission_check Chat::Agent.state(@session['id'], @data['data']['active']) diff --git a/lib/sessions/event/chat_base.rb b/lib/sessions/event/chat_base.rb index f630fa893..92a5ef153 100644 --- a/lib/sessions/event/chat_base.rb +++ b/lib/sessions/event/chat_base.rb @@ -53,4 +53,92 @@ class Sessions::Event::ChatBase } end + def agent_permission_check + if !@session + error = { + event: 'chat_error', + data: { + state: 'no_session', + }, + } + Sessions.send(@client_id, error) + return + end + if !@session['id'] + error = { + event: 'chat_error', + data: { + state: 'no_session_user_id', + }, + } + Sessions.send(@client_id, error) + return + end + user = User.lookup(id: @session['id']) + if !user + error = { + event: 'chat_error', + data: { + state: 'no_such_user', + }, + } + Sessions.send(@client_id, error) + return + end + if !user.role?('Agent') + error = { + event: 'chat_error', + data: { + state: 'no_permission', + }, + } + Sessions.send(@client_id, error) + return + end + true + end + + def current_chat_session + Chat::Session.find_by(session_id: @data['data']['session_id']) + end + + def check_chat_session_exists + if !@data['data'] || !@data['data']['session_id'] + error = { + event: 'chat_error', + data: { + state: 'Need session_id.', + }, + } + Sessions.send(@client_id, error) + return + end + return true if current_chat_session + error = { + event: 'chat_error', + data: { + state: "No such session id #{@data['data']['session_id']}", + }, + } + Sessions.send(@client_id, error) + false + end + + def current_chat + Chat.find_by(id: @data['data']['chat_id']) + end + + def check_chat_exists + chat = current_chat + return true if chat + error = { + event: 'chat_error', + data: { + state: 'no_such_chat', + }, + } + Sessions.send(@client_id, error) + false + end + end diff --git a/lib/sessions/event/chat_session_close.rb b/lib/sessions/event/chat_session_close.rb index 306e2c282..c5e945432 100644 --- a/lib/sessions/event/chat_session_close.rb +++ b/lib/sessions/event/chat_session_close.rb @@ -2,24 +2,7 @@ class Sessions::Event::ChatSessionClose < Sessions::Event::ChatBase def run - if !@data['data'] || !@data['data']['session_id'] - return { - event: 'chat_status_close', - data: { - state: 'Need session_id.', - }, - } - end - - chat_session = Chat::Session.find_by(session_id: @data['data']['session_id']) - if !chat_session - return { - event: 'chat_status_close', - data: { - state: "No such session id #{@data['data']['session_id']}", - }, - } - end + return if !check_chat_session_exists realname = 'Anonymous' if @session && @session['id'] @@ -28,6 +11,7 @@ class Sessions::Event::ChatSessionClose < Sessions::Event::ChatBase # check count of participents participents_count = 0 + chat_session = current_chat_session if chat_session.preferences[:participents] participents_count = chat_session.preferences[:participents].count end diff --git a/lib/sessions/event/chat_session_init.rb b/lib/sessions/event/chat_session_init.rb index 853173fbb..4edac5151 100644 --- a/lib/sessions/event/chat_session_init.rb +++ b/lib/sessions/event/chat_session_init.rb @@ -1,21 +1,11 @@ class Sessions::Event::ChatSessionInit < Sessions::Event::ChatBase def run - - chat_id = 1 - chat = Chat.find_by(id: chat_id) - if !chat - return { - event: 'chat_session_init', - data: { - state: 'no_such_chat', - }, - } - end + return if !check_chat_exists # create chat session chat_session = Chat::Session.create( - chat_id: chat_id, + chat_id: @data['data']['chat_id'], name: '', state: 'waiting', preferences: { diff --git a/lib/sessions/event/chat_session_message.rb b/lib/sessions/event/chat_session_message.rb index b454f7e17..46e317bbf 100644 --- a/lib/sessions/event/chat_session_message.rb +++ b/lib/sessions/event/chat_session_message.rb @@ -1,25 +1,8 @@ class Sessions::Event::ChatSessionMessage < Sessions::Event::ChatBase def run - - if !@data['data'] || !@data['data']['session_id'] - return { - event: 'chat_session_message', - data: { - state: 'Need session_id.', - }, - } - end - - chat_session = Chat::Session.find_by(session_id: @data['data']['session_id']) - if !chat_session - return { - event: 'chat_session_message', - data: { - state: "No such session id #{@data['data']['session_id']}", - }, - } - end + return if !check_chat_session_exists + chat_session = current_chat_session user_id = nil if @session diff --git a/lib/sessions/event/chat_session_start.rb b/lib/sessions/event/chat_session_start.rb index 0480c6259..0b5a7bbf5 100644 --- a/lib/sessions/event/chat_session_start.rb +++ b/lib/sessions/event/chat_session_start.rb @@ -1,6 +1,7 @@ class Sessions::Event::ChatSessionStart < Sessions::Event::ChatBase def run + agent_permission_check # find first in waiting list chat_session = Chat::Session.where(state: 'waiting').order('created_at ASC').first @@ -34,6 +35,7 @@ class Sessions::Event::ChatSessionStart < Sessions::Event::ChatBase state: 'ok', agent: user, session_id: chat_session.session_id, + chat_id: chat_session.chat_id, }, } chat_session.send_to_recipients(data) diff --git a/lib/sessions/event/chat_session_typing.rb b/lib/sessions/event/chat_session_typing.rb index c7180ce00..9ab4b109e 100644 --- a/lib/sessions/event/chat_session_typing.rb +++ b/lib/sessions/event/chat_session_typing.rb @@ -1,25 +1,8 @@ class Sessions::Event::ChatSessionTyping < Sessions::Event::ChatBase def run - - if !@data['data'] || !@data['data']['session_id'] - return { - event: 'chat_session_typing', - data: { - state: 'Need session_id.', - }, - } - end - - chat_session = Chat::Session.find_by(session_id: @data['data']['session_id']) - if !chat_session - return { - event: 'chat_session_typing', - data: { - state: "No such session id #{@data['data']['session_id']}", - }, - } - end + return if !check_chat_session_exists + chat_session = current_chat_session user_id = nil if @session diff --git a/lib/sessions/event/chat_status_agent.rb b/lib/sessions/event/chat_status_agent.rb index 7e723a118..9f0801d8d 100644 --- a/lib/sessions/event/chat_status_agent.rb +++ b/lib/sessions/event/chat_status_agent.rb @@ -3,6 +3,7 @@ class Sessions::Event::ChatStatusAgent < Sessions::Event::ChatBase def run # check if user has permissions + return if !agent_permission_check # renew timestamps state = Chat::Agent.state(@session['id']) diff --git a/lib/sessions/event/chat_status_customer.rb b/lib/sessions/event/chat_status_customer.rb index 5fa937e22..7dbeeeec6 100644 --- a/lib/sessions/event/chat_status_customer.rb +++ b/lib/sessions/event/chat_status_customer.rb @@ -1,17 +1,7 @@ class Sessions::Event::ChatStatusCustomer < Sessions::Event::ChatBase def run - - chat_id = 1 - chat = Chat.find_by(id: chat_id) - if !chat - return { - event: 'chat_status_customer', - data: { - state: 'no_such_chat', - }, - } - end + return if !check_chat_exists # check if it's a chat sessin reconnect session_id = nil @@ -24,7 +14,7 @@ class Sessions::Event::ChatStatusCustomer < Sessions::Event::ChatBase end { event: 'chat_status_customer', - data: chat.customer_state(session_id), + data: current_chat.customer_state(session_id), } end end