youtube chat association and more bug fixes

This commit is contained in:
Seth Call 2017-10-17 21:36:53 -05:00
parent 7e2268e9ce
commit 0e428c9922
18 changed files with 137 additions and 16 deletions

View File

@ -9,7 +9,7 @@ CREATE OR REPLACE FUNCTION sms_index (my_user_id VARCHAR, my_locidispid BIGINT,
-- XXX: we should pass in enough info to match pagination/query to reduce the impact of this step
INSERT INTO sms_music_session_tmp SELECT DISTINCT id, NULL::INTEGER AS tag, NULL::INTEGER AS latency
FROM music_sessions
WHERE (scheduled_start IS NULL OR scheduled_start > (NOW() - (interval '15 minute')))
WHERE old = FALSE AND (scheduled_start IS NULL OR scheduled_start > (NOW() - (interval '15 minute')))
AND canceled = FALSE AND description != 'Jam Track Session'
AND id NOT IN (SELECT id FROM active_music_sessions);
@ -204,6 +204,24 @@ CREATE INDEX index_music_sessions_on_canceled ON music_sessions USING btree(canc
CREATE INDEX index_music_sessions_on_session_removed_at ON music_sessions USING btree(session_removed_at);
CREATE INDEX index_music_sessions_on_started_at ON music_sessions USING btree(started_at);
CREATE INDEX index_recordings_on_first_quick_mix_id ON recordings USING btree(first_quick_mix_id);
CREATE INDEX index_recordings_on_has_final_mix ON recordings USING btree(has_final_mix);
CREATE INDEX index_quick_mixes_on_recording_id ON quick_mixes USING btree(recording_id);
CREATE INDEX index_quick_mixes_on_cleaned ON quick_mixes USING btree(cleaned);
CREATE INDEX index_quick_mixes_on_completed ON quick_mixes USING btree(completed);
CREATE INDEX index_recordings_on_deleted ON recordings USING btree(deleted);
CREATE INDEX index_recordings_on_all_discarded ON recordings USING btree(all_discarded);
CREATE INDEX index_claimed_recordings_on_is_public ON claimed_recordings USING btree(is_public);
CREATE INDEX index_claimed_recordings_on_recording_id ON claimed_recordings USING btree(recording_id);
CREATE INDEX index_charges_on_type ON charges USING btree(type);
CREATE INDEX index_charges_on_billing_should_retry ON charges USING btree(billing_should_retry);
CREATE INDEX index_lesson_sessions_on_charge_id ON lesson_sessions USING btree(charge_id);
CREATE INDEX index_music_sessions_on_lesson_session_id ON music_sessions USING btree(lesson_session_id);
CREATE INDEX index_lesson_sessions_on_status ON lesson_sessions USING btree(status);
CREATE INDEX index_lesson_sessions_on_sent_counter_reminder ON lesson_sessions USING btree(sent_counter_reminder);
-- update music_sessions set canceled = true WHERE (scheduled_start IS NULL OR scheduled_start > (NOW() - (interval '15 minute'))) AND canceled = FALSE AND description != 'Jam Track Session' AND id NOT IN (SELECT id FROM active_music_sessions) AND id NOT IN (select distinct on(name, user_id) id FROM music_sessions WHERE (scheduled_start IS NULL OR scheduled_start > (NOW() - (interval '15 minute'))) AND canceled = FALSE AND description != 'Jam Track Session' AND id NOT IN (SELECT id FROM active_music_sessions) order by name, user_id);

View File

@ -552,6 +552,10 @@ module JamRuby
icecast_server = IcecastServer.find_best_server_for_user(user) if music_session.fan_access
icecast_server.lock! if icecast_server
music_session.running_recordings.each do |recording|
recording.stop
end
# check if we are connected to rabbitmq
active_music_session = ActiveMusicSession.new
active_music_session.id = music_session.id # copy the .id from music_session to active_music_session

View File

@ -114,12 +114,19 @@ module JamRuby
attachment_type = music_notation.attachment_type
attachment_name = music_notation.file_name
elsif claimed_recording
attachment_id = claimed_recording.id
attachment_type = 'recording'
attachment_name = claimed_recording.name
if purpose == 'Video Uploaded'
attachment_id = claimed_recording.video_id
attachment_type = 'video'
else
attachment_id = claimed_recording.id
attachment_type = 'recording'
attachment_name = claimed_recording.name
end
end
msg = @@message_factory.chat_message(
music_session_id,
user.name,

View File

@ -31,6 +31,9 @@ module JamRuby
SHARE_TOKEN_LENGTH = 8
FIXNUM_MAX = (2**(0.size * 8 -2) -1)
def video_id
recording.external_video_id
end
def user_belongs_to_recording
if user && recording && !recording.users.exists?(user.id)

View File

@ -470,6 +470,10 @@ module JamRuby
active
end
def has_access?(user)
user.id == student.id || user.id == teacher.id || (self.school.nil? ? false : self.school.user.id == user.id)
end
def validate_accepted
# accept is multipe purpose; either accept the initial request, or a counter slot
if self.status_was != STATUS_REQUESTED && self.status_was != STATUS_COUNTERED

View File

@ -11,7 +11,7 @@ module JamRuby
@@log = Logging.logger[LessonSession]
delegate :sent_billing_notices, :last_billing_attempt_at, :billing_attempts, :billing_should_retry, :billed_at, :billing_error_detail, :billing_error_reason, :is_card_declined?, :is_card_expired?, :last_billed_at_date, :sent_billing_notices, to: :lesson_payment_charge, allow_nil: true
delegate :is_test_drive?, :is_single_free?, :is_normal?, :approved_before?, :is_active?, :recurring, :is_monthly_payment?, :school_on_school?, :school_on_school_payment?, :no_school_on_school_payment?, :payment_if_school_on_school?, :scheduling_email, :teacher_school_emails, :school_and_teacher, :school_over_teacher, :school_and_teacher_ids, :school_over_teacher_ids, :posa_card, :remaining_roll_forward_amount_in_cents, :has_recurring_counter?, :ever_accepted?, to: :lesson_booking
delegate :is_test_drive?, :is_single_free?, :is_normal?, :approved_before?, :is_active?, :recurring, :is_monthly_payment?, :school_on_school?, :school_on_school_payment?, :no_school_on_school_payment?, :payment_if_school_on_school?, :scheduling_email, :teacher_school_emails, :school_and_teacher, :school_over_teacher, :school_and_teacher_ids, :school_over_teacher_ids, :posa_card, :remaining_roll_forward_amount_in_cents, :has_recurring_counter?, :ever_accepted?, :has_access?, to: :lesson_booking
delegate :pretty_scheduled_start, to: :music_session
@ -338,6 +338,21 @@ module JamRuby
self.save(validate: false)
end
def video_uploaded(user, recording, data)
claim = recording.claim_for_user(user)
msg = ChatMessage.create(user, nil, "Video Recording '#{claim.name}'", ChatMessage::CHANNEL_LESSON, nil, other_user(user), self, "Video Uploaded", nil, claim)
Notification.send_lesson_message('video uploaded', self, false)
Notification.send_lesson_message('video uploaded', self, true)
end
def other_user(user)
if user.id == student.id
teacher
else
student
end
end
def session_completed
LessonSession.transaction do
self.lock!

View File

@ -482,10 +482,22 @@ module JamRuby
if self.musician_access || self.fan_access
true
else
self.creator == user || self.invited_musicians.exists?(user.id)
self.creator == user || self.invited_musicians.exists?(user.id) || self.approved_rsvps.include?(user) || self.has_lesson_access?(user)
end
end
def has_lesson_access?(user)
if is_lesson?
puts "HAS LESSON ACCESS"
result = lesson_session.has_access?(user)
puts "HAS LESSON ACCESS #{ result}"
result
else
false
end
end
def set_session_controller(current_user, user)
# only allow update of session controller by the creator or the currently marked user
@ -896,6 +908,9 @@ module JamRuby
RsvpRequest.index(self, nil, {status: 'pending'})
end
def running_recordings
recordings.where(duration: nil)
end
def recordings
Recording.where(music_session_id: self.id)
end

View File

@ -755,8 +755,12 @@ module JamRuby
self.save(:validate => false)
end
def add_video_data(data)
def add_video_data(user, data)
Recording.where(id: self.id).update_all(external_video_id: data[:video_id])
if music_session.music_session.is_lesson?
music_session.lesson_session.video_uploaded(user, self, data)
end
end
def add_timeline(timeline)

View File

@ -38,6 +38,10 @@ module JamRuby
auth.save
return auth
rescue Exception => e
puts "could not refresh; #{e}"
if auth
auth.destroy
end
# couldn't refresh; probably the user has revoked the app's rights
return nil
end

View File

@ -2,7 +2,7 @@ context = window
@ChatDialog = React.createClass({
mixins: [@PostProcessorMixin, Reflux.listenTo(@AppStore, "onAppInit")]
mixins: [@PostProcessorMixin, Reflux.listenTo(@AppStore, "onAppInit"), Reflux.listenTo(@SessionStore, 'onSessionChanged')]
teacher: false
beforeShow: (args) ->
@ -27,7 +27,8 @@ context = window
@app.ajaxError(jqXHR)
afterHide: () ->
window.ChatActions.activateChannel('global')
if !@session?.isLesson
window.ChatActions.activateChannel('global')
parseId:(id) ->
if !id?
@ -47,6 +48,9 @@ context = window
@app.bindDialog('chat-dialog', dialogBindings);
onSessionChanged: (session) ->
@session = session
componentDidMount: () ->
@root = $(@getDOMNode())

View File

@ -45,6 +45,7 @@ ChatActions = @ChatActions
when 'Audio File' then 'attached an audio file'
when 'JamKazam Recording' then 'attached a recording'
when 'Lesson Timeout' then 'canceled by system'
when 'Video Uploaded' then 'uploaded video'
else purpose
notationClicked: (music_notation, e) ->
@ -61,6 +62,10 @@ ChatActions = @ChatActions
e.preventDefault()
context.JK.popExternalLink("/recordings/#{recording.id}")
videoClicked: (recording, e) ->
e.preventDefault()
context.JK.popExternalLink("https://www.youtube.com/watch?v=#{recording.video_id}")
openMenu: (lesson, e) ->
$this = $(e.target)
if !$this.is('.lesson-session-actions-btn')
@ -132,6 +137,8 @@ ChatActions = @ChatActions
additional = `<a className="additional" onClick={this.audioClicked.bind(this, msg.music_notation)}>{msg.music_notation.file_name}</a>`
else if msg.purpose == 'JamKazam Recording'
additional = `<a className="additional" onClick={this.recordingClicked.bind(this, msg.claimed_recording)}>{msg.claimed_recording.name}</a>`
else if msg.purpose == 'Video Uploaded'
additional = `<a className="additional" onClick={this.videoClicked.bind(this, msg.claimed_recording)}>Watch on YouTube</a>`
msgs.push(`<div key={msg.msg_id} className="chat-message">
<span className="chat-message-sender">{sender}</span>{purpose}<time className="chat-message-timestamp timeago">{timeago}</time>
@ -209,6 +216,7 @@ ChatActions = @ChatActions
e.preventDefault()
@sendMessage()
handleCloseMessage: (e) ->
e.preventDefault()
this.props.onCloseClicked()

View File

@ -0,0 +1,18 @@
context = window
RecordingActions = @RecordingActions
@SessionFilesBtn = React.createClass({
getInitialState: () ->
{}
openLessonChat: () ->
this.props.app.layout.showDialog('chat-dialog', {d1: 'lesson_' + this.props.lessonId})
render: () ->
`<a className="session-record button-grey left" onClick={this.openLessonChat.bind(this)}>
<img src="/assets/content/icon_open_folder.png" align="texttop" height="14" width="14"/>
FILES
</a>`
})

View File

@ -3,17 +3,25 @@ MIX_MODES = context.JK.MIX_MODES
SessionActions = @SessionActions
@SessionScreen = React.createClass({
mixins: [Reflux.listenTo(@AppStore,"onAppInit"), Reflux.listenTo(@SessionActions.allowLeaveSession, "onAllowLeaveSession")]
mixins: [Reflux.listenTo(@AppStore,"onAppInit"), Reflux.listenTo(@SessionActions.allowLeaveSession, "onAllowLeaveSession"), Reflux.listenTo(@SessionStore,"onSessionStoreChanged")]
getInitialState: () ->
{isLesson: false, lessonId: null}
render: () ->
videoBtn = null
filesBtn = null
if gon.global.video_available != 'none'
videoBtn = `<SessionVideoBtn />`
if this.state.isLesson
filesBtn = `<SessionFilesBtn app={this.app} lessonId={this.state.lessonId}/>`
`<div className="session-container">
<div className="in-session-controls">
@ -22,6 +30,7 @@ SessionActions = @SessionActions
<SessionShareBtn />
<SessionRecordBtn />
{videoBtn}
{filesBtn}
<SessionMixerBtn />
<SessionResyncBtn />
<SessionLeaveBtn />
@ -70,6 +79,8 @@ SessionActions = @SessionActions
@logger.debug("session beforeDisconnect")
return { freezeInteraction: true };
onSessionStoreChanged: (session) ->
this.setState({isLesson: session.isLesson, lessonId: session.lessonId})
onAllowLeaveSession: () ->
@allowLeave = true

View File

@ -9,10 +9,15 @@ context = window
@isRecording = isRecording
@downloadingJamTrack = downloadingJamTrack
@preppingVstEnable = preppingVstEnable
@isLesson = @session?.lesson_session?
if @isLesson
@lessonId = @session.lesson_session.id
inSession: () ->
@session?
participants: () ->
if @session
return @session.participants

View File

@ -23,7 +23,7 @@ div[data-react-class="ChatWindow"] {
}
.additional {
margin-left:4px;
margin-left:0px;
display: block;
margin-top:4px;
}
@ -131,7 +131,7 @@ div[data-react-class="ChatWindow"] {
overflow: auto;
margin: 0px 15px;
/*height: 210px;*/
height: 100%;
height: 98%;
}
.chart-text-section {

View File

@ -10,7 +10,8 @@
}
.dialog-inner {
width: auto;
height:calc(100% - 29px)
height:calc(100% - 29px);
padding-top:3px;
}
div[data-react-class="ChatDialog"] {

View File

@ -477,7 +477,7 @@ class ApiRecordingsController < ApiController
end
def add_video_data
@recording.add_video_data(params)
@recording.add_video_data(current_user, params)
video_id = params[:video_id]
@ -488,7 +488,7 @@ class ApiRecordingsController < ApiController
body << "User: " + current_user.admin_url + "\n\n"
body << "Recording Landing: #{recording_detail_url(@recording.id)}\n"
private_public = @recording.is_public ? 'Public' : 'Private'
private_public = @recording.is_public? ? 'Public' : 'Private'
AdminMailer.social({
subject:"#{private_public } Video Uploaded by #{current_user.name}",
body:body

View File

@ -15,5 +15,5 @@ child :music_notation do
end
child :claimed_recording do
attributes :id, :name
attributes :id, :name, :video_id
end