diff --git a/db/manifest b/db/manifest index a94679598..af6d8c9c0 100755 --- a/db/manifest +++ b/db/manifest @@ -122,3 +122,4 @@ scores_create_schemas_and_extensions.sql scores_create_tables.sql remove_is_downloadable.sql scores_mod_connections2.sql +track_download_counts.sql diff --git a/db/up/track_download_counts.sql b/db/up/track_download_counts.sql new file mode 100644 index 000000000..f08d001a9 --- /dev/null +++ b/db/up/track_download_counts.sql @@ -0,0 +1,5 @@ +ALTER TABLE recorded_tracks ADD COLUMN download_count INTEGER NOT NULL DEFAULT 0; +ALTER TABLE recorded_tracks ADD COLUMN last_downloaded_at TIMESTAMP; + +ALTER TABLE mixes ADD COLUMN download_count INTEGER NOT NULL DEFAULT 0; +ALTER TABLE mixes ADD COLUMN last_downloaded_at TIMESTAMP; \ No newline at end of file diff --git a/ruby/lib/jam_ruby/models/claimed_recording.rb b/ruby/lib/jam_ruby/models/claimed_recording.rb index e7f8fbc4b..607eb053c 100644 --- a/ruby/lib/jam_ruby/models/claimed_recording.rb +++ b/ruby/lib/jam_ruby/models/claimed_recording.rb @@ -20,6 +20,7 @@ module JamRuby validates_uniqueness_of :user_id, :scope => :recording_id validate :user_belongs_to_recording + before_create :generate_share_token SHARE_TOKEN_LENGTH = 8 @@ -67,7 +68,6 @@ module JamRuby !ClaimedRecording.find_by_user_id_and_recording_id(some_user.id, recording_id).nil? end - def remove_non_alpha_num(token) token.gsub(/[^0-9A-Za-z]/, '') end diff --git a/ruby/lib/jam_ruby/models/mix.rb b/ruby/lib/jam_ruby/models/mix.rb index 216145a2e..0d2282b0c 100644 --- a/ruby/lib/jam_ruby/models/mix.rb +++ b/ruby/lib/jam_ruby/models/mix.rb @@ -10,14 +10,24 @@ module JamRuby attr_accessible :ogg_url, :should_retry, as: :admin attr_accessor :is_skip_mount_uploader + attr_writer :current_user belongs_to :recording, :class_name => "JamRuby::Recording", :inverse_of => :mixes, :foreign_key => 'recording_id' + validates :download_count, presence: true + validate :verify_download_count + skip_callback :save, :before, :store_picture!, if: :is_skip_mount_uploader mount_uploader :ogg_url, MixUploader + def verify_download_count + if (self.download_count < 0 || self.download_count > APP_CONFIG.max_audio_downloads) && !@current_user.admin + errors.add(:download_count, "must be less than or equal to 100") + end + end + before_validation do # this should be an activeadmin only path, because it's using the mount_uploader (whereas the client does something completely different) if !is_skip_mount_uploader && ogg_url.present? && ogg_url.respond_to?(:file) && ogg_url_changed? @@ -67,7 +77,6 @@ module JamRuby !ClaimedRecording.find_by_user_id_and_recording_id(some_user.id, recording_id).nil? end - def errored(reason, detail) self.error_reason = reason self.error_detail = detail @@ -148,6 +157,11 @@ module JamRuby Mix.construct_filename(self.created_at, self.recording_id, self.id, type) end + def update_download_count(count=1) + self.download_count = self.download_count + count + self.last_downloaded_at = Time.now + end + private def delete_s3_files diff --git a/ruby/lib/jam_ruby/models/music_session_history.rb b/ruby/lib/jam_ruby/models/music_session_history.rb index f728493b5..553c03bac 100644 --- a/ruby/lib/jam_ruby/models/music_session_history.rb +++ b/ruby/lib/jam_ruby/models/music_session_history.rb @@ -173,8 +173,6 @@ module JamRuby hist.end_history if hist - puts "**************NOTIFICATION SESSION ENDED**************" - Notification.send_session_ended(session_id) end diff --git a/ruby/lib/jam_ruby/models/notification.rb b/ruby/lib/jam_ruby/models/notification.rb index ab6708ca4..6bb3ec67a 100644 --- a/ruby/lib/jam_ruby/models/notification.rb +++ b/ruby/lib/jam_ruby/models/notification.rb @@ -357,7 +357,6 @@ module JamRuby # publish to all users who have a notification for this session # TODO: do this in BULK or in async block notifications.each do |n| - puts "*************SENDING SESSION_ENDED TO #{n.target_user_id}***************" msg = @@message_factory.session_ended(n.target_user_id, session_id) @@mq_router.publish_to_user(n.target_user_id, msg) end diff --git a/ruby/lib/jam_ruby/models/recorded_track.rb b/ruby/lib/jam_ruby/models/recorded_track.rb index 21e15cf6e..0dc498996 100644 --- a/ruby/lib/jam_ruby/models/recorded_track.rb +++ b/ruby/lib/jam_ruby/models/recorded_track.rb @@ -12,6 +12,7 @@ module JamRuby attr_writer :is_skip_mount_uploader attr_accessible :discard, :user, :user_id, :instrument_id, :sound, :client_id, :track_id, :client_track_id, :url, as: :admin + attr_writer :current_user SOUND = %w(mono stereo) MAX_PART_FAILURES = 3 @@ -31,11 +32,13 @@ module JamRuby validates :length, length: {minimum: 1, maximum: 1024 * 1024 * 256 }, if: :upload_starting? # 256 megs max. is this reasonable? surely... validates :user, presence: true validates :instrument, presence: true + validates :download_count, presence: true before_destroy :delete_s3_files validate :validate_fully_uploaded validate :validate_part_complete validate :validate_too_many_upload_failures + validate :verify_download_count before_save :sanitize_active_admin skip_callback :save, :before, :store_picture!, if: :is_skip_mount_uploader? @@ -97,6 +100,12 @@ module JamRuby end end + def verify_download_count + if (self.download_count < 0 || self.download_count > APP_CONFIG.max_audio_downloads) && !@current_user.admin + errors.add(:download_count, "must be less than or equal to 100") + end + end + def sanitize_active_admin self.user_id = nil if self.user_id == '' end @@ -187,6 +196,11 @@ module JamRuby RecordedTrack.construct_filename(self.created_at, self.recording.id, self.client_track_id) end + def update_download_count(count=1) + self.download_count = self.download_count + count + self.last_downloaded_at = Time.now + end + private def delete_s3_files diff --git a/ruby/spec/factories.rb b/ruby/spec/factories.rb index 69bb70a09..a0a6cdbfd 100644 --- a/ruby/spec/factories.rb +++ b/ruby/spec/factories.rb @@ -171,10 +171,28 @@ FactoryGirl.define do association :user, factory: :user before(:create) { |claimed_recording| - claimed_recording.recording = FactoryGirl.create(:recording_with_track, owner: claimed_recording.user) unless claimed_recording.recording } + + end + + factory :mix, :class => JamRuby::Mix do + started_at Time.now + completed_at Time.now + ogg_md5 'abc' + ogg_length 1 + sequence(:ogg_url) { |n| "recordings/ogg/#{n}" } + mp3_md5 'abc' + mp3_length 1 + sequence(:mp3_url) { |n| "recordings/mp3/#{n}" } + completed true + + before(:create) {|mix| + user = FactoryGirl.create(:user) + mix.recording = FactoryGirl.create(:recording_with_track, owner: user) + mix.recording.claimed_recordings << FactoryGirl.create(:claimed_recording, user: user, recording: mix.recording) + } end factory :musician_instrument, :class => JamRuby::MusicianInstrument do diff --git a/ruby/spec/jam_ruby/models/mix_spec.rb b/ruby/spec/jam_ruby/models/mix_spec.rb index 150b305e8..7296140a1 100755 --- a/ruby/spec/jam_ruby/models/mix_spec.rb +++ b/ruby/spec/jam_ruby/models/mix_spec.rb @@ -63,6 +63,16 @@ describe Mix do recordings.length.should == 0 end + + describe "download count" do + it "will fail if too high" do + mix = FactoryGirl.create(:mix) + mix.current_user = mix.recording.owner + mix.update_download_count(APP_CONFIG.max_audio_downloads + 1) + mix.save + mix.errors[:download_count].should == ["must be less than or equal to 100"] + end + end end diff --git a/ruby/spec/spec_helper.rb b/ruby/spec/spec_helper.rb index 60f32513b..f1df45da8 100644 --- a/ruby/spec/spec_helper.rb +++ b/ruby/spec/spec_helper.rb @@ -13,6 +13,9 @@ SpecDb::recreate_database # initialize ActiveRecord's db connection ActiveRecord::Base.establish_connection(YAML::load(File.open('config/database.yml'))["test"]) +# so jam_ruby models that use APP_CONFIG in metadata will load. this is later stubbed pre test run +APP_CONFIG = app_config + require 'jam_ruby' require 'factory_girl' require 'rubygems' diff --git a/ruby/spec/support/utilities.rb b/ruby/spec/support/utilities.rb index ef2e28292..ab6c023f3 100644 --- a/ruby/spec/support/utilities.rb +++ b/ruby/spec/support/utilities.rb @@ -101,6 +101,10 @@ def app_config '315576000' end + def max_audio_downloads + 100 + end + private def audiomixer_workspace_path diff --git a/web/app/assets/javascripts/accounts_identity.js b/web/app/assets/javascripts/accounts_identity.js index 66a1d80a6..7d7ef1019 100644 --- a/web/app/assets/javascripts/accounts_identity.js +++ b/web/app/assets/javascripts/accounts_identity.js @@ -209,7 +209,7 @@ var password_confirmation_errors = context.JK.format_errors("password_confirmation", errors) if(current_password_errors != null) { - $('#account-edit-password-form #account-forgot-password').closest('div.field').addClass('error').end().after(current_password_errors); + $('#account-edit-password-form input[name=current_password]').closest('div.field').addClass('error').end().after(current_password_errors); } if(password_errors != null) { diff --git a/web/app/assets/javascripts/bandProfile.js b/web/app/assets/javascripts/bandProfile.js index 20ff38afc..7027661ea 100644 --- a/web/app/assets/javascripts/bandProfile.js +++ b/web/app/assets/javascripts/bandProfile.js @@ -47,55 +47,53 @@ /****************** MAIN PORTION OF SCREEN *****************/ function addFollowing(isBand, id) { - var newFollowing = {}; + var newFollowing = {}; - if (!isBand) { - newFollowing.user_id = id; - } - else { - newFollowing.band_id = id; - } + if (!isBand) { + newFollowing.user_id = id; + } + else { + newFollowing.band_id = id; + } - rest.addFollowing(newFollowing) - .done(function() { - if (isBand) { - var newCount = parseInt($("#band-profile-follower-stats").text()) + 1; - var text = newCount > 1 || newCount == 0 ? " Followers" : " Follower"; - $('#band-profile-follower-stats').html(newCount + text); - configureBandFollowingButton(true); - } - else { - configureMemberFollowingButton(true, id); - } - }) - .fail(app.ajaxError); + rest.addFollowing(newFollowing) + .done(function() { + if (isBand) { + var newCount = parseInt($("#band-profile-follower-stats").text()) + 1; + var text = newCount > 1 || newCount == 0 ? " Followers" : " Follower"; + $('#band-profile-follower-stats').html(newCount + text); + configureBandFollowingButton(true); + } + else { + configureMemberFollowingButton(true, id); + } + renderActive(); + }) + .fail(app.ajaxError); } function removeFollowing(isBand, id) { - var following = {}; - following.target_entity_id = id; - - rest.removeFollowing(following) - .done(function() { - renderActive(); // refresh stats - if (isBand) { - var newCount = parseInt($("#band-profile-follower-stats").text()) - 1; - var text = newCount > 1 || newCount == 0 ? " Followers" : " Follower"; - $('#band-profile-follower-stats').html(newCount + text); - configureBandFollowingButton(false); - } - else { - configureMemberFollowingButton(false, id); - } - }) - .fail(app.ajaxError); + rest.removeFollowing(id) + .done(function() { + if (isBand) { + var newCount = parseInt($("#band-profile-follower-stats").text()) - 1; + var text = newCount > 1 || newCount == 0 ? " Followers" : " Follower"; + $('#band-profile-follower-stats').html(newCount + text); + configureBandFollowingButton(false); + } + else { + configureMemberFollowingButton(false, id); + } + renderActive(); + }) + .fail(app.ajaxError); } function configureBandFollowingButton(following) { $('#btn-follow-band').unbind("click"); if (following) { - $('#btn-follow-band').text('STOP FOLLOWING'); + $('#btn-follow-band').text('UNFOLLOW'); $('#btn-follow-band').click(function() { removeFollowing(true, bandId); return false; @@ -121,7 +119,7 @@ $btnFollowMember.unbind("click"); if (following) { - $btnFollowMember.text('UN-FOLLOW'); + $btnFollowMember.text('UNFOLLOW'); $btnFollowMember.click(function() { removeFollowing(false, userId); return false; diff --git a/web/app/assets/javascripts/ftue.js b/web/app/assets/javascripts/ftue.js index 2823888ef..e51581602 100644 --- a/web/app/assets/javascripts/ftue.js +++ b/web/app/assets/javascripts/ftue.js @@ -487,7 +487,7 @@ * Load available drivers and populate the driver select box. */ function loadAudioDrivers() { - var drivers = jamClient.FTUEGetDevices(); + var drivers = jamClient.FTUEGetDevices(false); var driverOptionFunc = function (driverKey, index, list) { optionsHtml += '