diff --git a/ruby/lib/jam_ruby/app/mailers/user_mailer.rb b/ruby/lib/jam_ruby/app/mailers/user_mailer.rb index 6bccf6e58..b5f055419 100644 --- a/ruby/lib/jam_ruby/app/mailers/user_mailer.rb +++ b/ruby/lib/jam_ruby/app/mailers/user_mailer.rb @@ -1770,5 +1770,28 @@ module JamRuby format.html { render :layout => "from_user_mailer" } end end + + def lesson_attachment(sender, target, lesson_session, attachment) + @sender = sender + @target = target + @lesson_session = lesson_session + @attachment = attachment + + + email = target.email + @subject = "An attachment has been added to your lesson by #{sender.name}" + unique_args = {:type => "lesson_attachment"} + + sendgrid_category "Notification" + sendgrid_unique_args :type => unique_args[:type] + sendgrid_recipients([email]) + sendgrid_substitute('@USERID', [@target.id]) + + mail(:to => email, :subject => @subject) do |format| + format.text + format.html { render :layout => "from_user_mailer" } + end + + end end end diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/lesson_attachment.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/lesson_attachment.html.erb new file mode 100644 index 000000000..fc49d2163 --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/lesson_attachment.html.erb @@ -0,0 +1,20 @@ +<% provide(:title, @subject) %> +<% provide(:photo_url, @sender.resolved_photo_url) %> + +<% content_for :note do %> +

+ <% if @attachment.is_a?(JamRuby::MusicNotation) %> + <% if @attachment.is_notation? %> + A music notation has been added to your lesson. You can download "><%= @attachment.file_name %> directly or at any time in the message window for this lesson. + <% else %> + A audio file has been added to your lesson. You can download "><%= @attachment.file_name %> directly or at any time in the message window for this lesson. + <% end %> + <% else %> + A recording named "<%= @attachment.name %>" has been added to your lesson. It can be viewed ">here or found within the message window for this lesson. + <% end %> +

+ VIEW LESSON DETAILS +

+<% end %> + + diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/lesson_attachment.text.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/lesson_attachment.text.erb new file mode 100644 index 000000000..8756d460c --- /dev/null +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/lesson_attachment.text.erb @@ -0,0 +1,12 @@ +<% if @attachment.is_a?(JamRuby::MusicNotation) %> +<% if @attachment.is_notation? %> +A music notation has been added to your lesson. You can download (<%= APP_CONFIG.external_root_url + "/api/music_notations/#{@attachment.id}" %>">)<%= @attachment.file_name %> directly or at any time in the message window for this lesson. +<% else %> +A audio file has been added to your lesson. You can download (<%= APP_CONFIG.external_root_url + "/api/music_notations/#{@attachment.id}" %>">)<%= @attachment.file_name %> directly or at any time in the message window for this lesson. +<% end %> +<% else %> +A recording named "<%= @attachment.name %>" has been added to your lesson. It can be viewed (<%= APP_CONFIG.external_root_url + "/recordings/#{@attachment.id}" %>">) here or found within the message window for this lesson. +<% end %> +VIEW LESSON DETAILS (<%= @lesson_session.web_url %>) + + diff --git a/ruby/lib/jam_ruby/models/music_notation.rb b/ruby/lib/jam_ruby/models/music_notation.rb index 767453d14..21406b384 100644 --- a/ruby/lib/jam_ruby/models/music_notation.rb +++ b/ruby/lib/jam_ruby/models/music_notation.rb @@ -48,6 +48,9 @@ module JamRuby s3_manager.sign_url(self[:file_url], {:expires => expiration_time, :secure => true}) end + def is_notation? + self.attachment_type == TYPE_NOTATION + end private def self.construct_filename(notation) diff --git a/ruby/spec/factories.rb b/ruby/spec/factories.rb index 4a3b6a247..8cde0eff7 100644 --- a/ruby/spec/factories.rb +++ b/ruby/spec/factories.rb @@ -1057,5 +1057,13 @@ FactoryGirl.define do factory :email_blacklist, class: "JamRuby::EmailBlacklist" do sequence(:email) { |n| "person_#{n}@example.com"} end + + factory :music_notation, class: "JamRuby::MusicNotation" do + attachment_type {JamRuby::MusicNotation::TYPE_NOTATION} + association :user, factory: :user + file_url 'abc' + size 100 + file_name 'some_file.jpg' + end end diff --git a/ruby/spec/mailers/render_emails_spec.rb b/ruby/spec/mailers/render_emails_spec.rb index ae09837eb..ea653fe61 100644 --- a/ruby/spec/mailers/render_emails_spec.rb +++ b/ruby/spec/mailers/render_emails_spec.rb @@ -162,6 +162,26 @@ describe "RenderMailers", :slow => true do UserMailer.deliveries.clear UserMailer.lesson_starting_soon_student(lesson).deliver end + + it "music_notation_attachment" do + @filename = "music_notation_attachment" + + lesson = testdrive_lesson(user, teacher) + + UserMailer.deliveries.clear + notation = FactoryGirl.create(:music_notation, user: user) + UserMailer.lesson_attachment(user, teacher, lesson, notation).deliver + end + + it "recording_attachment" do + @filename = "recording_attachment" + + lesson = testdrive_lesson(user, teacher) + + UserMailer.deliveries.clear + claim = FactoryGirl.create(:claimed_recording, user: user) + UserMailer.lesson_attachment(user, teacher, lesson, claim).deliver + end end end diff --git a/web/app/assets/javascripts/react-components/AttachmentStatus.js.jsx.coffee b/web/app/assets/javascripts/react-components/AttachmentStatus.js.jsx.coffee index 733cd77b9..75f5f84be 100644 --- a/web/app/assets/javascripts/react-components/AttachmentStatus.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/AttachmentStatus.js.jsx.coffee @@ -24,7 +24,7 @@ AttachmentStore = context.AttachmentStore notationUploadDone: () -> logger.debug("AttachmentStatus: notationUploadDone") - context.JK.Banner.showNotice('Notation Uploaded', 'The music notation file has been uploaded, and can be accessed from the Messages window for this lesson.') + #context.JK.Banner.showNotice('Notation Uploaded', 'The music notation file has been uploaded, and can be accessed from the Messages window for this lesson.') notationUploadFail: () -> logger.debug("AttachmentStatus: notationUploadFail") @@ -32,11 +32,11 @@ AttachmentStore = context.AttachmentStore audioSelected: (e) -> files = $(e.target).get(0).files logger.debug("audio files selected: ", files) - window.AttachmentActions.uploadAudio.trigger(files, @notationUploadDone, @notationUploadFail) + window.AttachmentActions.uploadAudios.trigger(files, @notationUploadDone, @notationUploadFail) audioUploadDone: () -> logger.debug("AttachmentStatus: audioUploadDone") - context.JK.Banner.showNotice('Audio file Uploaded', 'The audio file has been uploaded, and can be accessed from the Messages window for this lesson.') + #context.JK.Banner.showNotice('Audio file Uploaded', 'The audio file has been uploaded, and can be accessed from the Messages window for this lesson.') audioUploadFail: () -> logger.debug("AttachmentStatus: audioUploadFail") diff --git a/web/app/assets/javascripts/react-components/MusicNotationUploadDialog.js.jsx.coffee b/web/app/assets/javascripts/react-components/MusicNotationUploadDialog.js.jsx.coffee new file mode 100644 index 000000000..067a95186 --- /dev/null +++ b/web/app/assets/javascripts/react-components/MusicNotationUploadDialog.js.jsx.coffee @@ -0,0 +1,49 @@ +context = window + +@MusicNotationUploadDialog = React.createClass({ + + mixins: [Reflux.listenTo(@AppStore, "onAppInit"), Reflux.listenTo(AttachmentStore, "onAttachmentStore")] + + getInitialState: () -> + { + uploading: false + } + onAppInit: (@app) -> + + onAttachmentStore: (attachmentState) -> + @setState(attachmentState) + + handleCloseMessage: (e) -> + e.preventDefault() + + @app.layout.closeDialog('music-notation-upload-dialog') + + render: () -> + + if @state.uploading + state = + `
+

Please wait while we upload your attachment to the lesson...

+
+
` + else + state = + `
+

Your file has been uploaded.

+
` + + `
+
+ + +

Uploading Attachment

+
+
+ {state} +
+ CLOSE +
+
+
` +}) + diff --git a/web/app/assets/javascripts/react-components/actions/AttachmentActions.js.coffee b/web/app/assets/javascripts/react-components/actions/AttachmentActions.js.coffee index b744ca86e..78ff35912 100644 --- a/web/app/assets/javascripts/react-components/actions/AttachmentActions.js.coffee +++ b/web/app/assets/javascripts/react-components/actions/AttachmentActions.js.coffee @@ -5,4 +5,5 @@ context = window startAttachNotation: {} startAttachAudio: {} uploadNotations: {} + uploadAudios: {} }) diff --git a/web/app/assets/javascripts/react-components/stores/AttachmentStore.js.coffee b/web/app/assets/javascripts/react-components/stores/AttachmentStore.js.coffee index a24cdcd85..e6d795ab7 100644 --- a/web/app/assets/javascripts/react-components/stores/AttachmentStore.js.coffee +++ b/web/app/assets/javascripts/react-components/stores/AttachmentStore.js.coffee @@ -105,6 +105,8 @@ AttachmentActions = @AttachmentActions formData.append('lesson_session_id', @lessonId); formData.append('attachment_type', 'notation') + @app.layout.showDialog('music-notation-upload-dialog') + rest.uploadMusicNotations(formData) .done((response) => @doneUploadingNotatations(notations, response, doneCallback, failCallback)) .fail((jqXHR) => @failUploadingNotations(jqXHR, failCallback)) @@ -137,6 +139,71 @@ AttachmentActions = @AttachmentActions else @app.notifyServerError(jqXHR, "Unable to upload music notations"); + onUploadAudios: (notations, doneCallback, failCallback) -> + logger.debug("beginning upload of audio", notations) + @uploading = true + @changed() + + formData = new FormData() + maxExceeded = false; + $.each(notations, (i, file) => ( + max = 10 * 1024 * 1024; + if file.size > max + maxExceeded = true + return false + + formData.append('files[]', file) + )) + + if maxExceeded + @app.notify({ + title: "Maximum Music Audio Size Exceeded", + text: "You can only upload files up to 10 megabytes in size." + }) + failCallback() + @uploading = false + @changed() + return + + + formData.append('lesson_session_id', @lessonId); + formData.append('attachment_type', 'audio') + + @app.layout.showDialog('music-notation-upload-dialog') + + rest.uploadMusicNotations(formData) + .done((response) => @doneUploadingAudios(notations, response, doneCallback, failCallback)) + .fail((jqXHR) => @failUploadingAudios(jqXHR, failCallback)) + + doneUploadingAudios: (notations, response, doneCallback, failCallback) -> + @uploading = false + @changed() + error_files = []; + $.each(response, (i, music_notation) => ( + if music_notation.errors + error_files.push(notations[i].name) + ) + ) + if error_files.length > 0 + failCallback() + @app.notifyAlert("Failed to upload audio files.", error_files.join(', ')); + else + doneCallback() + + failUploadingAudios: (jqXHR, failCallback) -> + @uploading = false + @changed() + if jqXHR.status == 413 + # the file is too big. Let the user know. + # This should happen when they select the file, but a misconfiguration on the server could cause this. + @app.notify({ + title: "Maximum Music Audio Size Exceeded", + text: "You can only upload files up to 10 megabytes in size." + }) + else + @app.notifyServerError(jqXHR, "Unable to upload music audio files"); + + changed: () -> this.trigger({lessonId: @lessonId, uploading: @uploading}) } diff --git a/web/app/assets/stylesheets/dialogs/MusicNotationUploadDialog.css.scss b/web/app/assets/stylesheets/dialogs/MusicNotationUploadDialog.css.scss new file mode 100644 index 000000000..6c280b210 --- /dev/null +++ b/web/app/assets/stylesheets/dialogs/MusicNotationUploadDialog.css.scss @@ -0,0 +1,35 @@ +@import "client/common"; + +#music-notation-upload-dialog { + width: 500px; + max-height:500px; + + h3 { + color:white; + margin-bottom:20px; + } + .dialog-inner { + width: auto; + height:100%; + @include border_box_sizing; + margin-top: -29px; + padding: 50px 25px 25px; + } + + div[data-react-class="MusicNotationUploadDialog"] { + + } + .MusicNotationUploadDialog { + height:100%; + } + .spinner-large { + width:200px; + height:200px; + line-height: 200px; + position:relative; + margin:25px auto; + } + .actions { + text-align:right; + } +} \ No newline at end of file diff --git a/web/app/views/dialogs/_dialogs.html.haml b/web/app/views/dialogs/_dialogs.html.haml index 4c0ed3f1d..6d51c6828 100644 --- a/web/app/views/dialogs/_dialogs.html.haml +++ b/web/app/views/dialogs/_dialogs.html.haml @@ -54,3 +54,4 @@ = render 'dialogs/cancelLessonDialog' = render 'dialogs/rescheduleLessonDialog' = render 'dialogs/rateUserDialog' += render 'dialogs/musicNotationUploadDialog' \ No newline at end of file diff --git a/web/app/views/dialogs/_musicNotationUploadDialog.html.slim b/web/app/views/dialogs/_musicNotationUploadDialog.html.slim new file mode 100644 index 000000000..e9470ba87 --- /dev/null +++ b/web/app/views/dialogs/_musicNotationUploadDialog.html.slim @@ -0,0 +1,2 @@ +.dialog.dialog-overlay-sm.top-parent layout='dialog' layout-id='music-notation-upload-dialog' id='music-notation-upload-dialog' + = react_component 'MusicNotationUploadDialog', {}