diff --git a/db/manifest b/db/manifest
index 1250059b1..89fd895c4 100755
--- a/db/manifest
+++ b/db/manifest
@@ -327,4 +327,5 @@ populate_languages.sql
populate_subjects.sql
reviews.sql
download_tracker_fingerprints.sql
-connection_active.sql
\ No newline at end of file
+connection_active.sql
+chat_channel.sql
\ No newline at end of file
diff --git a/db/up/chat_channel.sql b/db/up/chat_channel.sql
new file mode 100644
index 000000000..1e94e7e16
--- /dev/null
+++ b/db/up/chat_channel.sql
@@ -0,0 +1,2 @@
+ALTER TABLE chat_messages ADD COLUMN channel VARCHAR(128) NOT NULL DEFAULT 'session';
+ADD INDEX
\ No newline at end of file
diff --git a/ruby/lib/jam_ruby/jam_track_importer.rb b/ruby/lib/jam_ruby/jam_track_importer.rb
index 01fed9be0..36b1a8655 100644
--- a/ruby/lib/jam_ruby/jam_track_importer.rb
+++ b/ruby/lib/jam_ruby/jam_track_importer.rb
@@ -2603,8 +2603,13 @@ module JamRuby
def generate_jmeps
importers = []
+ if is_tency_storage?
+ licensor = JamTrackLicensor.find_by_name!('Tency Music')
+ elsif is_paris_storage?
+ licensor = JamTrackLicensor.find_by_name!('Paris Music')
+ end
- JamTrack.all.each do |jam_track|
+ JamTrack.where(licensor_id: licensor).each do |jam_track|
importers << generate_jmep(jam_track)
end
diff --git a/ruby/lib/jam_ruby/models/chat_message.rb b/ruby/lib/jam_ruby/models/chat_message.rb
index 005187415..fc7b51929 100644
--- a/ruby/lib/jam_ruby/models/chat_message.rb
+++ b/ruby/lib/jam_ruby/models/chat_message.rb
@@ -32,7 +32,7 @@ module JamRuby
music_session_id = params[:music_session]
query = ChatMessage.where('music_session_id = ?', music_session_id)
- .offset(start).limit(limit)
+ .offset(start).limit(limit)
if query.length == 0
[query, nil]
@@ -43,21 +43,25 @@ module JamRuby
end
end
- def send_chat_msg(music_session, chat_msg, user, client_id)
+ def send_chat_msg(music_session, chat_msg, user, client_id, channel)
+ music_session_id = music_session.id if music_session
+
msg = @@message_factory.chat_message(
- music_session.id,
+ music_session_id,
user.name,
user.id,
chat_msg.message,
chat_msg.id,
chat_msg.created_at.utc.iso8601,
- 'session'
+ channel
)
- @@mq_router.server_publish_to_session(music_session, msg, sender = {:client_id => client_id})
+ if channel == 'session'
+ @@mq_router.server_publish_to_session(music_session, msg, sender = {:client_id => client_id})
+ elsif channel == 'global'
+ @@mq_router.publish_to_active_clients(msg)
+ end
end
-
end
-
end
end
\ No newline at end of file
diff --git a/ruby/lib/jam_ruby/mq_router.rb b/ruby/lib/jam_ruby/mq_router.rb
index c7a9ba417..be4ee21c6 100644
--- a/ruby/lib/jam_ruby/mq_router.rb
+++ b/ruby/lib/jam_ruby/mq_router.rb
@@ -70,6 +70,12 @@ class MQRouter
publish_to_client(MessageFactory::ALL_NATIVE_CLIENTS, client_msg)
end
+
+ # sends a message to all clients
+ def publish_to_active_clients(client_msg)
+ publish_to_client(MessageFactory::ALL_ACTIVE_CLIENTS, client_msg)
+ end
+
# sends a message to a session with no checking of permissions (RAW USAGE)
# this method deliberately has no database interactivity/active_record objects
def publish_to_session(music_session_id, client_ids, client_msg, sender = {:client_id => nil})
diff --git a/web/app/assets/javascripts/chatPanel.js b/web/app/assets/javascripts/chatPanel.js
index 45a13014b..fa6033939 100644
--- a/web/app/assets/javascripts/chatPanel.js
+++ b/web/app/assets/javascripts/chatPanel.js
@@ -30,8 +30,8 @@
fullyInitialized = false;
renderQueue = [];
sendingMessage = false;
- $chatMessages.empty();
- $textBox.val('');
+ //$chatMessages.empty();
+ //$textBox.val('');
}
function buildMessage() {
@@ -135,7 +135,7 @@
}
function events(bind) {
- if (bind) {
+ /**if (bind) {
$form.submit(sendMessage);
$textBox.keydown(handleEnter);
$sendChatMessageBtn.click(sendMessage);
@@ -144,28 +144,27 @@
$form.submit(null);
$textBox.keydown(null);
$sendChatMessageBtn.click(null);
- }
+ }*/
- registerChatMessage(bind);
}
// called from sidebar when messages come in
function chatMessageReceived(payload) {
- if(fullyInitialized) {
- if (isChatPanelVisible()) {
- renderMessage(payload.msg, payload.sender_id, payload.sender_name, payload.created_at, true);
- }
- else {
+ //if(fullyInitialized) {
+ //if (isChatPanelVisible()) {
+ // renderMessage(payload.msg, payload.sender_id, payload.sender_name, payload.created_at, true);
+ //}
+ //else {
highlightCount();
incrementChatCount();
- renderQueue.push({message: payload.msg, user_id: payload.sender_id, user_name: payload.sender_name, sent: payload.created_at});
+ // renderQueue.push({message: payload.msg, user_id: payload.sender_id, user_name: payload.sender_name, sent: payload.created_at});
context.jamClient.UserAttention(true);
- }
- }
- else {
- renderQueue.push({message: payload.msg, user_id: payload.sender_id, user_name: payload.sender_name, sent: payload.created_at});
- }
+ //}
+ //}
+ //else {
+ // renderQueue.push({message: payload.msg, user_id: payload.sender_id, user_name: payload.sender_name, sent: payload.created_at});
+ //}
}
function registerChatMessage(bind) {
@@ -173,6 +172,7 @@
context.JK.JamServer.registerMessageCallback(context.JK.MessageType.CHAT_MESSAGE, function(header, payload) {
logger.debug("Handling CHAT_MESSAGE msg " + JSON.stringify(payload));
chatMessageReceived(payload);
+ context.ChatActions.msgReceived(payload);
handledNotification(payload);
});
@@ -193,8 +193,8 @@
$sessionId = data.session.id;
// open chat panel
- $chatSender.show();
- $chatMessagesScroller.show();
+ //$chatSender.show();
+ //$chatMessagesScroller.show();
$errorMsg.hide();
$panel.find('.panel-header').trigger('click');
$panel.on('open', opened);
@@ -202,12 +202,15 @@
reset();
+ context.ChatActions.sessionStarted($sessionId);
+
// load previous chat messages
rest.getChatMessages(buildQuery())
.done(function (response) {
- handleChatResponse(response);
+ //handleChatResponse(response);
- scrollToBottom(true);
+ context.ChatActions.loadMessages('session', response)
+ //scrollToBottom(true);
showing = true;
fullyInitialized = true;
drainQueue();
@@ -318,20 +321,22 @@
$contents = $panel.find('.chatcontents');
$chatMessagesScroller = $panel.find('.chat-list-scroller');
$count = $panel.find('#sidebar-chat-count');
- $chatMessages = $panel.find('.previous-chat-list');
- $sendChatMessageBtn = $panel.find('.btn-send-chat-message');
- $chatSender = $panel.find('.chat-sender');
- $form = $panel.find('.chat-message-form');
- $textBox = $form.find('textarea');
+ //$chatMessages = $panel.find('.previous-chat-list');
+ //$sendChatMessageBtn = $panel.find('.btn-send-chat-message');
+ //$chatSender = $panel.find('.chat-sender');
+ //$form = $panel.find('.chat-message-form');
+ //$textBox = $form.find('textarea');
$errorMsg = $panel.find('.chat-status');
$errorMsg.show();
- $chatSender.hide();
- $chatMessagesScroller.hide();
+ //$chatSender.hide();
+ //$chatMessagesScroller.hide();
app.user()
.done(function (userDetail) {
user = userDetail;
+
+ registerChatMessage(true);
});
}
diff --git a/web/app/assets/javascripts/react-components/ChatWindow.js.jsx.coffee b/web/app/assets/javascripts/react-components/ChatWindow.js.jsx.coffee
index 415eaae52..d0e739387 100644
--- a/web/app/assets/javascripts/react-components/ChatWindow.js.jsx.coffee
+++ b/web/app/assets/javascripts/react-components/ChatWindow.js.jsx.coffee
@@ -1,16 +1,145 @@
context = window
-MIX_MODES = context.JK.MIX_MODES
+rest = new context.JK.Rest()
+ChatActions = @ChatActions
@ChatWindow = React.createClass({
- mixins: [Reflux.listenTo(@AppStore, "onAppInit"), Reflux.listenTo(@UserStore, "onUserChanged"), Reflux.listenTo(@ChatStore, "onChatChanged")]
+ mixins: [Reflux.listenTo(@AppStore, "onAppInit"), Reflux.listenTo(@UserStore, "onUserChanged"),
+ Reflux.listenTo(@ChatStore, "onChatChanged")]
+
+ lastChannel: null
getInitialState: () ->
- {channels:['global', 'session']}
+ state = context.ChatStore.getState()
+ state
+
+ onChatChanged: (chatState) ->
+ @setState(chatState)
+
+ onUserChanged: (userState) ->
+ @setState(userState)
+
+ onAppInit: (app) ->
+ @app = app
+
+ activateChannel: (channel, e) ->
+ e.preventDefault()
+ ChatActions.activateChannel(channel);
render: () ->
+ tabs = []
+
+ for channel of @state.msgs
+ classes = {}
+ classes[channel] = true
+ classes['chat-tab'] = true
+ classes['active'] = channel == @state.channel
+
+ if channel == 'global'
+ display = 'Global'
+ else if channel == 'session'
+ display = 'Session'
+ else if !channel?
+ display = 'Global'
+ else
+ display = 'Unknown'
+
+ tabs.push(`
`)
+
+ msgs = []
+ activeMsgs = @state.msgs[@state.channel] || []
+
+ for msg in activeMsgs
+
+ timeago = $.timeago(msg.created_at)
+ if msg.sender_id == context.JK.currentUserId
+ sender = "me"
+ else
+ sender = msg.sender_name
+
+ msgs.push(`
+ {sender}
+ {msg.msg}
+
+
`)
+
`
-
`
+
+ sendMessage:()->
+ if !context.JK.JamServer.connected
+ return false
+
+ msg = @textBox.val()
+ logger.debug("text box: " + msg)
+ if !msg? || msg == ''
+ # don't bother the server with empty messages
+ return false;
+
+ if !@sendingMessage
+ @sendingMessage = true
+ ChatActions.sendMsg(msg, @sendMsgDone, @sendMsgFail)
+
+ sendMsgDone: () ->
+ @textBox.val('')
+ @sendingMessage = false
+
+ sendMsgFail: (jqXHR) ->
+ @app.notifyServerError(jqXHR, 'Unable to Send Chat Message')
+ @sendingMessage = false
+
+ handleSendMessage: (e) ->
+ e.preventDefault()
+ @sendMessage()
+
+ componentDidMount: () ->
+ @root = $(@getDOMNode())
+ @textBox = @root.find('textarea')
+
+ componentDidUpdate: () ->
+ if @lastChannel != @state.channel
+ speed = 0
+ else
+ speed = 'slow'
+ @lastChannel = @state.channel
+
+ speed = 0 #slow
+ $scroller = @root.find('.chat-list-scroller')
+ @root.animate({scrollTop: $scroller[0].scrollHeight}, speed)
+
+ pasteIntoInput: (el, text) ->
+ el.focus();
+ if typeof el.selectionStart == "number" && typeof el.selectionEnd == "number"
+ val = el.value
+ selStart = el.selectionStart
+ el.value = val.slice(0, selStart) + text + val.slice(el.selectionEnd)
+ el.selectionEnd = el.selectionStart = selStart + text.length
+ else if typeof document.selection != "undefined"
+ textRange = document.selection.createRange()
+ textRange.text = text
+ textRange.collapse(false)
+ textRange.select()
+
+ handleEnter: (evt) ->
+ if evt.keyCode == 13 && evt.shiftKey
+ evt.preventDefault()
+ @pasteIntoInput(this, "\n")
+ else if evt.keyCode == 13 && !evt.shiftKey
+ @sendMessage()
+ return false
})
\ No newline at end of file
diff --git a/web/app/assets/javascripts/react-components/actions/ChatActions.js.coffee b/web/app/assets/javascripts/react-components/actions/ChatActions.js.coffee
index 5d99548b0..41b65f36a 100644
--- a/web/app/assets/javascripts/react-components/actions/ChatActions.js.coffee
+++ b/web/app/assets/javascripts/react-components/actions/ChatActions.js.coffee
@@ -3,4 +3,8 @@ context = window
@ChatActions = Reflux.createActions({
msgReceived: {}
sendMsg: {}
+ loadMessages: {}
+ emptyChannel: {}
+ sessionStarted: {}
+ activateChannel: {}
})
diff --git a/web/app/assets/javascripts/react-components/stores/ChatStore.js.coffee b/web/app/assets/javascripts/react-components/stores/ChatStore.js.coffee
index 207136212..9e504ca2c 100644
--- a/web/app/assets/javascripts/react-components/stores/ChatStore.js.coffee
+++ b/web/app/assets/javascripts/react-components/stores/ChatStore.js.coffee
@@ -6,14 +6,57 @@ logger = context.JK.logger
{
listenables: @ChatActions
- channel: null,
- msgs: {}
+ channel: 'global',
+ msgs: {global:[], session:[]}
- init: ->
+ init: () ->
# Register with the app store to get @app
this.listenTo(context.AppStore, this.onAppInit)
onAppInit: (@app) ->
+ #$(document).on(EVENTS.SESSION_STARTED, ((e, data) =>
+ #@sessionStarted(e, data);
+ # return false
+ #))
+
+ # $(context.AppStore).on('SessionStarted', @onSessionStarted)
+
+ # called from ChatPanel
+ onSessionStarted: () ->
+ logger.debug("ChatStore: onSessionStarted")
+ @msgs['session'] = []
+ @channel = 'session'
+ @textBox.val('')
+ @onEmptyChannel(@channel)
+
+ onEmptyChannel: (channel) ->
+ @msgs[channel] = []
+ @changed()
+
+ convertServerMessages: (chats) ->
+ converted = []
+ for chat in chats
+ convert = {}
+ convert.sender_name = chat.user?.name
+ convert.sender_id = chat.user_id
+ convert.msg = chat.message
+ convert.msg_id = chat.id
+ convert.created_at = chat.created_at
+ convert.channel = chat.channel
+ converted
+
+ # called from ChatPanel
+ onLoadMessages: (channel, msgs) ->
+ channelMsgs = @msgs[channel]
+
+ if !channelMsgs?
+ channelMsgs = []
+ @msgs[channel] = channelMsgs
+
+ history = @convertServerMessages(msgs.chats)
+
+ @msgs[channel] = history.concat(channelMsgs)
+ @changed()
onMsgReceived: (msg) ->
logger.debug("ChatStore.msgReceived", msg)
@@ -27,12 +70,49 @@ logger = context.JK.logger
channelMsgs.push(msg)
@changed()
- onSendMsg: (msg) ->
+ buildMessage:(msg) ->
+ payload = {message: msg}
+ if @channel == 'session'
+ payload.music_session = SessionStore.currentSessionId
+ payload.channel = @channel
+ payload.client_id = @app.clientId
+ payload
+
+ onActivateChannel: (channel) ->
+ @channel = channel
+ @changed()
+
+ onSendMsg: (msg, done, fail) ->
+ rest.createChatMessage(@buildMessage(msg))
+ .done((response) =>
+
+ done(response)
+
+ console.log("ON SEND MESSAGE SIMULATE", response)
+
+ @onMsgReceived({
+ sender_name: context.JK.currentUserName
+ sender_id: context.JK.currentuserId
+ msg: msg,
+ msg_id: response.id,
+ created_at: response.created_at,
+ channel: @channel
+ })
+ )
+ .fail((jqXHR) =>
+ fail(jqXHR)
+ )
+
+ # unused/untested. send direct to gateway
+ onSendMsgInstant: (msg) ->
logger.debug("ChatStore.sendMsg", msg)
window.JK.JamServer.sendChatMessage(@channel, msg)
+ getState: () ->
+ return {msgs: @msgs, channel: @channel}
+
changed: () ->
- @trigger(msgs)
+ @trigger(@getState())
}
)
diff --git a/web/app/assets/stylesheets/client/react-components/ChatWindow.css.scss b/web/app/assets/stylesheets/client/react-components/ChatWindow.css.scss
new file mode 100644
index 000000000..f17b2a68a
--- /dev/null
+++ b/web/app/assets/stylesheets/client/react-components/ChatWindow.css.scss
@@ -0,0 +1,104 @@
+div[data-react-class="ChatWindow"] {
+ height:100%;
+
+ .ChatWindow {
+ height:100%;
+ }
+
+ .chat-tabs {
+ text-align:center;
+ }
+ .chat-tab {
+
+ margin:0 2px;
+ display:inline-block;
+
+ padding:2px;
+ color: #ED3618;
+ background-color:#09525b;
+ border-style:solid;
+ border-color:#09525b;
+ border-width:1px;
+
+ a {
+ //color:white;
+ text-decoration: underline;
+ }
+
+ &.active {
+ a {
+ text-decoration: none;
+ }
+ background-color:transparent;
+ border-color:#09525b;
+ border-width:0;
+ }
+ }
+
+
+ .chat-list-scroller {
+ position: relative;
+ display: block;
+ overflow: auto;
+ margin: 0px 15px;
+ /*height: 210px;*/
+ height: 73%;
+ }
+ .chart-text-section {
+
+ }
+
+ .btn-send-chat-message {
+ float:right;
+ margin: 3px 0 0;
+ }
+
+ #new-chat-message {
+ width: calc(100% - 70px);
+ height: 20px;
+ }
+
+ .chat-status {
+ line-height: 20px;
+ text-align: center;
+ padding: 10px;
+ }
+
+ .chat-message {
+ margin:5px 0;
+
+ .chat-message-sender {
+ font-weight:bold;
+ margin-right:10px;
+ color: #ED3618;
+
+ &:after {
+ content:':'
+ }
+ }
+
+ .chat-message-text {
+ line-height:18px;
+ white-space:pre-line;
+ color: #D5E2E4;
+ }
+
+ .chat-message-timestamp {
+ margin-top:4px;
+ color:#AAA;
+ display:block;
+ font-size:12px;
+ }
+ }
+
+ .chat-sender {
+ width: 100%;
+ position: absolute;
+ bottom: 7px;
+ padding: 0px 7px;
+ /* height: 20%; */
+ /* min-height: 69px; */
+ box-sizing: border-box;
+ }
+
+}
\ No newline at end of file
diff --git a/web/app/assets/stylesheets/client/sidebar.css.scss b/web/app/assets/stylesheets/client/sidebar.css.scss
index 59a3bdfb5..58c058f8f 100644
--- a/web/app/assets/stylesheets/client/sidebar.css.scss
+++ b/web/app/assets/stylesheets/client/sidebar.css.scss
@@ -180,69 +180,6 @@
position: relative;
}
- .chat-list-scroller {
- position: relative;
- display: block;
- overflow: auto;
- margin: 0px 15px;
- /*height: 210px;*/
- height: 73%;
- }
- .chart-text-section {
-
- }
-
- .btn-send-chat-message {
- margin-top: 5px;
- margin-right: 30px;
- }
-
- #new-chat-message {
- width: 90%;
- height: 40px;
- }
-
- .chat-status {
- line-height: 20px;
- text-align: center;
- padding: 10px;
- }
-
- .chat-message {
- margin:5px 0;
-
- .chat-message-sender {
- font-weight:bold;
- margin-right:10px;
- color: #ED3618;
-
- &:after {
- content:':'
- }
- }
-
- .chat-message-text {
- line-height:18px;
- white-space:pre-line;
- color: #D5E2E4;
- }
-
- .chat-message-timestamp {
- margin-top:4px;
- color:#AAA;
- display:block;
- font-size:12px;
- }
- }
-
- .chat-sender {
- width: 100%;
- position: absolute;
- bottom: 10px;
- padding: 0px 15px;
- height: 20%;
- min-height: 69px;
- }
em {
color:#9DB8AF
diff --git a/web/app/controllers/api_chats_controller.rb b/web/app/controllers/api_chats_controller.rb
index 70988b845..26bd1bac9 100644
--- a/web/app/controllers/api_chats_controller.rb
+++ b/web/app/controllers/api_chats_controller.rb
@@ -7,11 +7,11 @@ class ApiChatsController < ApiController
def create
@chat_msg = ChatMessage.new
@chat_msg.user_id = current_user.id
- @chat_msg.music_session_id = @music_session.id
+ @chat_msg.music_session_id = @music_session.id if @music_session
@chat_msg.message = params[:message]
if @chat_msg.save
- ChatMessage.send_chat_msg @music_session, @chat_msg, current_user, params[:client_id]
+ ChatMessage.send_chat_msg @music_session, @chat_msg, current_user, params[:client_id], params[:channel]
end
respond_with_model(@chat_msg)
@@ -25,14 +25,17 @@ class ApiChatsController < ApiController
end
def check_session
- @music_session = ActiveMusicSession.find(params[:music_session])
- if @music_session.nil?
- raise ArgumentError, 'specified session not found'
+ if params.has_key?(:music_session)
+ @music_session = ActiveMusicSession.find(params[:music_session])
+ if @music_session.nil?
+ raise ArgumentError, 'specified session not found'
+ end
+
+ unless @music_session.access? current_user
+ raise JamPermissionError, 'not allowed to join the specified session'
+ end
end
- unless @music_session.access? current_user
- raise JamPermissionError, 'not allowed to join the specified session'
- end
end
end
\ No newline at end of file
diff --git a/web/app/views/api_chats/show.rabl b/web/app/views/api_chats/show.rabl
index d6ff4caa3..828e09f21 100644
--- a/web/app/views/api_chats/show.rabl
+++ b/web/app/views/api_chats/show.rabl
@@ -1,6 +1,6 @@
object @chat
-attributes :message, :user_id, :session_id, :created_at
+attributes :id, :message, :user_id, :session_id, :created_at, :channel
node :user do |c|
user_data = {}
diff --git a/web/app/views/clients/_sidebar.html.erb b/web/app/views/clients/_sidebar.html.erb
index b8d44dc68..8c8efaa7f 100644
--- a/web/app/views/clients/_sidebar.html.erb
+++ b/web/app/views/clients/_sidebar.html.erb
@@ -101,7 +101,9 @@
chat
-
+ <%= react_component 'ChatWindow', {} %>
+
+