diff --git a/admin/app/admin/chat_messages.rb b/admin/app/admin/chat_messages.rb new file mode 100644 index 000000000..29dfaed52 --- /dev/null +++ b/admin/app/admin/chat_messages.rb @@ -0,0 +1,23 @@ +ActiveAdmin.register JamRuby::ChatMessage, :as => 'ChatMessage' do + # Note: a lame thing is it's not obvious how to make it search on email instead of user_id. + filter :music_session_id + filter :user_id + + menu :parent => 'Misc' + + config.per_page = 200 + + config.sort_order = 'created_at DESC' + + index do + column 'User' do |oo| link_to(oo.user.email, oo.user.admin_url, {:title => oo.user.email}) end + column "Timestamp" do |post| + (post.created_at).strftime('%b %d %Y, %H:%M') + end + column "Message" do |post| + post.message + end + actions + + end +end diff --git a/db/up/chat_channel.sql b/db/up/chat_channel.sql index 1e94e7e16..ea0cbba75 100644 --- a/db/up/chat_channel.sql +++ b/db/up/chat_channel.sql @@ -1,2 +1,4 @@ ALTER TABLE chat_messages ADD COLUMN channel VARCHAR(128) NOT NULL DEFAULT 'session'; -ADD INDEX \ No newline at end of file +CREATE INDEX chat_messages_idx_channels ON chat_messages(channel); +CREATE INDEX chat_messages_idx_created_at ON chat_messages(created_at); +CREATE INDEX chat_messages_idx_music_session_id ON chat_messages(music_session_id); \ No newline at end of file diff --git a/ruby/lib/jam_ruby/models/chat_message.rb b/ruby/lib/jam_ruby/models/chat_message.rb index fc7b51929..8e650bad7 100644 --- a/ruby/lib/jam_ruby/models/chat_message.rb +++ b/ruby/lib/jam_ruby/models/chat_message.rb @@ -29,10 +29,14 @@ module JamRuby start = params[:start].presence start = start.to_i || 0 - music_session_id = params[:music_session] + query = ChatMessage.where('channel = ?', params[:channel]) - query = ChatMessage.where('music_session_id = ?', music_session_id) - .offset(start).limit(limit) + if params.has_key? (:music_session) + music_session_id = params[:music_session] + query = ChatMessage.where('music_session_id = ?', music_session_id) + end + + query = query.offset(start).limit(limit).order('created_at DESC') if query.length == 0 [query, nil] diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index b8e99e6cd..c99b36bcd 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -1230,7 +1230,11 @@ module JamRuby user.errors.add(:email, "is not real") end elsif result == "risky" || result == "unknown" - user.email_needs_verification = true + if response.body["disposable"] + user.errors.add(:email, "is disposable address") + else + user.email_needs_verification = true + end end else user.email_needs_verification = false diff --git a/web/app/assets/javascripts/JamServer.js b/web/app/assets/javascripts/JamServer.js index 0f6c48cbe..139f86a89 100644 --- a/web/app/assets/javascripts/JamServer.js +++ b/web/app/assets/javascripts/JamServer.js @@ -295,11 +295,15 @@ function markAway() { logger.debug("sleep again!") active = false; + context.UserActivityActions.setActive(active) + var userStatus = msg_factory.userStatus(false, null); + server.send(userStatus); } function activityCheck() { var timeoutTime = 300000; // 5 * 1000 * 60 , 5 minutes active = true; + context.UserActivityActions.setActive(active) activityTimeout = setTimeout(markAway, timeoutTime); $(document).ready(function() { $('body').bind('mousedown keydown touchstart focus', function(event) { @@ -316,6 +320,7 @@ } } active = true; + context.UserActivityActions.setActive(active) activityTimeout = setTimeout(markAway, timeoutTime); }); }); diff --git a/web/app/assets/javascripts/chatPanel.js b/web/app/assets/javascripts/chatPanel.js index fa6033939..32aaf043c 100644 --- a/web/app/assets/javascripts/chatPanel.js +++ b/web/app/assets/javascripts/chatPanel.js @@ -1,8 +1,8 @@ -(function(context,$) { +(function (context, $) { "use strict"; context.JK = context.JK || {}; - context.JK.ChatPanel = function(app) { + context.JK.ChatPanel = function (app) { var logger = context.JK.logger; var rest = context.JK.Rest(); var $panel = null; @@ -18,7 +18,7 @@ var $errorMsg = null; var sendingMessage = false; var showing = false; - var fullyInitialized = false; + var fullyInitialized = true; var renderQueue = []; var sidebar = null; var user = null; @@ -27,7 +27,7 @@ var next = null; function reset() { - fullyInitialized = false; + fullyInitialized = true; renderQueue = []; sendingMessage = false; //$chatMessages.empty(); @@ -45,28 +45,28 @@ } function sendMessage() { - if(!context.JK.JamServer.connected) { + if (!context.JK.JamServer.connected) { return false; } var msg = $textBox.val(); - if(!msg || msg == '') { + if (!msg || msg == '') { // don't bother the server with empty messages return false; } - if(!sendingMessage) { + if (!sendingMessage) { sendingMessage = true; rest.createChatMessage(buildMessage()) - .done(function() { + .done(function () { $textBox.val(''); renderMessage(msg, user.id, user.name, new Date().toISOString(), true); }) - .fail(function(jqXHR) { + .fail(function (jqXHR) { app.notifyServerError(jqXHR, 'Unable to Send Chat Message'); }) - .always(function() { + .always(function () { sendingMessage = false; }) @@ -84,9 +84,9 @@ sender: senderId == user.id ? 'me' : senderName, sent: sent }; - var txt = $(context._.template($('#template-chat-message').html(), options, { variable: 'data' })); + var txt = $(context._.template($('#template-chat-message').html(), options, {variable: 'data'})); txt.find('.timeago').timeago(); - if(append) { + if (append) { $chatMessages.append(txt); scrollToBottom(); } @@ -96,7 +96,7 @@ } function drainQueue() { - context._.each(renderQueue, function(msg) { + context._.each(renderQueue, function (msg) { renderMessage(msg.message, msg.user_id, msg.user_name, msg.sent, true); }); renderQueue = []; @@ -128,7 +128,7 @@ evt.preventDefault(); pasteIntoInput(this, "\n"); } - else if(evt.keyCode == 13 && !evt.shiftKey){ + else if (evt.keyCode == 13 && !evt.shiftKey) { sendMessage(); return false; } @@ -140,7 +140,7 @@ $textBox.keydown(handleEnter); $sendChatMessageBtn.click(sendMessage); } - else { + else { $form.submit(null); $textBox.keydown(null); $sendChatMessageBtn.click(null); @@ -150,26 +150,21 @@ // 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()) { + + } + else { highlightCount(); incrementChatCount(); - // 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}); - //} + } + } } function registerChatMessage(bind) { if (bind && bind == true) { - context.JK.JamServer.registerMessageCallback(context.JK.MessageType.CHAT_MESSAGE, function(header, payload) { + 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); @@ -185,10 +180,13 @@ function opened() { lowlightCount(); setCount(0); - drainQueue(); } + function fullyOpened() { + context.ChatActions.fullyOpened() + } + function sessionStarted(e, data) { $sessionId = data.session.id; @@ -197,36 +195,23 @@ //$chatMessagesScroller.show(); $errorMsg.hide(); $panel.find('.panel-header').trigger('click'); - $panel.on('open', opened); $panel.find('.btn-next-pager').attr('href', '/api/sessions/' + $sessionId + '/chats?page=1'); reset(); context.ChatActions.sessionStarted($sessionId); - - // load previous chat messages - rest.getChatMessages(buildQuery()) - .done(function (response) { - //handleChatResponse(response); - - context.ChatActions.loadMessages('session', response) - //scrollToBottom(true); - showing = true; - fullyInitialized = true; - drainQueue(); - }) - .fail(function (jqXHR) { - app.notifyServerError(jqXHR, 'Unable to Load Session Conversations') - }); + showing = true + fullyInitialized = true; + drainQueue(); events(true); } function sessionStopped(e, data) { // open chat panel - $chatSender.hide(); - $chatMessagesScroller.hide(); - $errorMsg.show(); + //$chatSender.hide(); + //$chatMessagesScroller.hide(); + //$errorMsg.show(); reset(); events(false); @@ -254,9 +239,9 @@ } function buildQuery() { - var query = {type: 'CHAT_MESSAGE', music_session: $sessionId, limit:LIMIT, page:currentPage}; + var query = {type: 'CHAT_MESSAGE', music_session: $sessionId, limit: LIMIT, page: currentPage}; - if(next) { + if (next) { query.start = next; } @@ -274,11 +259,11 @@ renderChats(response.chats); - if(response.next == null) { + if (response.next == null) { // if we less results than asked for, end searching $chatMessagesScroller.infinitescroll('pause'); - if(currentPage > 0) { + if (currentPage > 0) { // there are bugs with infinitescroll not removing the 'loading'. // it's most noticeable at the end of the list, so whack all such entries $('.infinite-scroll-loader').remove(); @@ -306,10 +291,10 @@ msg: $('
Loading ...
'), img: '/assets/shared/spinner-32.gif' }, - path: function(page) { + path: function (page) { return '/api/sessions/' + $sessionId + '/chats?' + $.param(buildQuery()); } - },function(json, opts) { + }, function (json, opts) { handleChatResponse(json); }); $chatMessagesScroller.infinitescroll('resume'); @@ -321,30 +306,26 @@ $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'); + $errorMsg = $panel.find('.chat-status'); - $errorMsg.show(); - //$chatSender.hide(); - //$chatMessagesScroller.hide(); + $panel.on('open', opened); + $panel.on('fullyOpen', fullyOpened); app.user() .done(function (userDetail) { user = userDetail; registerChatMessage(true); + }); } this.initialize = initialize; this.sessionStarted = sessionStarted; - this.sessionStopped = sessionStopped; + this.sessionStopped = sessionStopped; this.registerChatMessage = registerChatMessage; }; return this; -})(window,jQuery); \ No newline at end of file +})(window, jQuery); \ No newline at end of file diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index 953b9e0a7..b45cf5325 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -1711,11 +1711,9 @@ } function getChatMessages(options) { - var musciSessionId = options["music_session"]; - delete options["music_session"]; return $.ajax({ type: "GET", - url: '/api/sessions/' + musciSessionId + '/chats?' + $.param(options), + url: '/api/chat?' + $.param(options), dataType: "json", contentType: 'application/json' }) diff --git a/web/app/assets/javascripts/layout.js b/web/app/assets/javascripts/layout.js index 3ea51c8be..19a25056c 100644 --- a/web/app/assets/javascripts/layout.js +++ b/web/app/assets/javascripts/layout.js @@ -290,7 +290,9 @@ $('[layout-panel="contents"]').css({"height": "1px"}); $expandedPanelContents.show(); $expandedPanel.triggerHandler('open') - $expandedPanelContents.animate({"height": expandedPanelHeight + "px"}, opts.animationDuration); + $expandedPanelContents.animate({"height": expandedPanelHeight + "px"}, opts.animationDuration, function() { + $expandedPanel.triggerHandler('fullyOpen') + }); } function layoutHeader(screenWidth, screenHeight) { diff --git a/web/app/assets/javascripts/react-components.js b/web/app/assets/javascripts/react-components.js index 8c4e9b8db..aa06843e3 100644 --- a/web/app/assets/javascripts/react-components.js +++ b/web/app/assets/javascripts/react-components.js @@ -3,18 +3,20 @@ //= require_directory ./react-components/helpers //= require_directory ./react-components/actions //= require ./react-components/stores/AppStore +//= require ./react-components/stores/UserStore +//= require ./react-components/stores/UserActivityStore //= require ./react-components/stores/InstrumentStore //= require ./react-components/stores/LanguageStore //= require ./react-components/stores/GenreStore //= require ./react-components/stores/SubjectStore //= require ./react-components/stores/ProfileStore //= require ./react-components/stores/PlatformStore -//= require ./react-components/stores/ChatStore //= require ./react-components/stores/BrowserMediaStore //= require ./react-components/stores/RecordingStore //= require ./react-components/stores/VideoStore //= require ./react-components/stores/SessionStore //= require ./react-components/stores/SessionStatsStore +//= require ./react-components/stores/ChatStore //= require ./react-components/stores/MixerStore //= require ./react-components/stores/ConfigureTracksStore //= require ./react-components/stores/JamTrackStore 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 d0e739387..3aa8172dc 100644 --- a/web/app/assets/javascripts/react-components/ChatWindow.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/ChatWindow.js.jsx.coffee @@ -86,7 +86,6 @@ ChatActions = @ChatActions return false msg = @textBox.val() - logger.debug("text box: " + msg) if !msg? || msg == '' # don't bother the server with empty messages return false; @@ -100,7 +99,10 @@ ChatActions = @ChatActions @sendingMessage = false sendMsgFail: (jqXHR) -> - @app.notifyServerError(jqXHR, 'Unable to Send Chat Message') + if jqXHR.status == 404 + @app.notifyServerError(jqXHR, 'Session chat is only available while in session.') + else + @app.notifyServerError(jqXHR, 'Unable to Send Chat Message') @sendingMessage = false handleSendMessage: (e) -> @@ -118,9 +120,9 @@ ChatActions = @ChatActions speed = 'slow' @lastChannel = @state.channel - speed = 0 #slow + #speed = 0 #slow $scroller = @root.find('.chat-list-scroller') - @root.animate({scrollTop: $scroller[0].scrollHeight}, speed) + $scroller.animate({scrollTop: $scroller[0].scrollHeight}, speed) pasteIntoInput: (el, text) -> el.focus(); @@ -138,8 +140,7 @@ ChatActions = @ChatActions handleEnter: (evt) -> if evt.keyCode == 13 && evt.shiftKey evt.preventDefault() - @pasteIntoInput(this, "\n") + @pasteIntoInput($(evt.target).get(0), "\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/JamTrackLandingScreen.js.jsx.coffee b/web/app/assets/javascripts/react-components/JamTrackLandingScreen.js.jsx.coffee index 0a0b8922f..c5d09b153 100644 --- a/web/app/assets/javascripts/react-components/JamTrackLandingScreen.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/JamTrackLandingScreen.js.jsx.coffee @@ -37,7 +37,7 @@ rest = context.JK.Rest() playJamTracks = [] for jamTrack in @state.purchasedJamTracks - playJamTracks.push ` + playJamTracks.push ` {jamTrack.name} by {jamTrack.original_artist}` if @state.purchasedJamTracks.length < 5 diff --git a/web/app/assets/javascripts/react-components/TeacherExperienceEditableList.js.jsx.coffee b/web/app/assets/javascripts/react-components/TeacherExperienceEditableList.js.jsx.coffee index 0177cb7ed..e6f720de5 100644 --- a/web/app/assets/javascripts/react-components/TeacherExperienceEditableList.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/TeacherExperienceEditableList.js.jsx.coffee @@ -78,7 +78,7 @@ logger = context.JK.logger errors = [] if this.state.errors? for error in this.state.errors - errors.push(`{error}`) + errors.push(`{error}`) `
diff --git a/web/app/assets/javascripts/react-components/YearSelect.js.jsx.coffee b/web/app/assets/javascripts/react-components/YearSelect.js.jsx.coffee index 483eb347e..9b543533e 100644 --- a/web/app/assets/javascripts/react-components/YearSelect.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/YearSelect.js.jsx.coffee @@ -10,7 +10,7 @@ logger = context.JK.logger now = new Date().getFullYear() for yr in [now..1916] - options.push `` + options.push `` `