VRFS-1960 : download API for JamTracks, including a new message type, rescue job that builds the JKZ, and specs that exercise it all.
This commit is contained in:
parent
795cb6f536
commit
34cb617f5f
|
|
@ -32,9 +32,12 @@ ALTER TABLE jam_track_rights
|
|||
ADD COLUMN download_count INTEGER NOT NULL DEFAULT 0,
|
||||
ADD COLUMN signed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
ADD COLUMN downloaded_since_sign BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
ADD COLUMN last_downloaded_at timestamp without time zone NULL,
|
||||
ADD COLUMN created_at timestamp without time zone NOT NULL,
|
||||
ADD COLUMN updated_at timestamp without time zone NOT NULL,
|
||||
ALTER COLUMN jam_track_id TYPE BIGINT USING 0,
|
||||
ALTER COLUMN jam_track_id SET NOT NULL,
|
||||
ADD CONSTRAINT jam_track_rights_user_id_fkey FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
ADD CONSTRAINT jam_track_rights_jam_track_id_fkey FOREIGN KEY(jam_track_id) REFERENCES jam_tracks(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE notifications ADD COLUMN jam_track_right_id BIGINT REFERENCES jam_track_rights(id);
|
||||
|
|
@ -74,6 +74,9 @@ message ClientMessage {
|
|||
SOURCE_UP = 252;
|
||||
SOURCE_DOWN = 253;
|
||||
|
||||
// jamtracks notifications
|
||||
JAM_TRACK_SIGN_COMPLETE = 260;
|
||||
|
||||
TEST_SESSION_MESSAGE = 295;
|
||||
|
||||
PING_REQUEST = 300;
|
||||
|
|
@ -172,6 +175,9 @@ message ClientMessage {
|
|||
optional SourceUp source_up = 252;
|
||||
optional SourceDown source_down = 253;
|
||||
|
||||
// jamtracks notification
|
||||
optional JamTrackSignComplete jam_track_sign_complete=260;
|
||||
|
||||
// Client-Session messages (to/from)
|
||||
optional TestSessionMessage test_session_message = 295;
|
||||
|
||||
|
|
@ -586,6 +592,10 @@ message SourceDown {
|
|||
optional string music_session = 1; // music session id
|
||||
}
|
||||
|
||||
message JamTrackSignComplete {
|
||||
required string jam_track_right = 1; // jam track right id
|
||||
}
|
||||
|
||||
// route_to: session
|
||||
// a test message used by ruby-client currently. just gives way to send out to rest of session
|
||||
message TestSessionMessage {
|
||||
|
|
|
|||
|
|
@ -26,9 +26,12 @@ module JamRuby
|
|||
nm.gsub!(" ", "_")
|
||||
track_filename = File.join(tmp_dir, nm)
|
||||
track_url = jam_track_track.sign_url
|
||||
puts "track_url: #{track_url}"
|
||||
copy_url_to_file(track_url, track_filename)
|
||||
copy_url_to_file(track_url, File.join(".", nm))
|
||||
jam_file_opts << " -i '#{track_filename}+#{jam_track_track.part}'"
|
||||
end
|
||||
puts "LS + " + `ls -la '#{tmp_dir}'`
|
||||
|
||||
sku=jam_track.id
|
||||
title=jam_track.name
|
||||
|
|
@ -44,11 +47,11 @@ module JamRuby
|
|||
err = stderr.read(1000)
|
||||
out = stdout.read(1000)
|
||||
#puts "stdout: #{out}, stderr: #{err}"
|
||||
raise ArgumentError, "Error calling python script: #{out}" if out && (out.index("No track files specified") || out.index("Cannot find file"))
|
||||
raise ArgumentError, "Error calling python script: #{err}" if err.present?
|
||||
raise ArgumentError, "Error calling python script: #{out}" if out && (out.index("No track files specified") || out.index("Cannot find file"))
|
||||
jam_track_right[:url]
|
||||
|
||||
jam_track_right.url.store!(File.open(output_jkz))
|
||||
jam_track_right.url.store!(File.open(output_jkz, "rb"))
|
||||
jam_track_right.signed=true
|
||||
jam_track_right.downloaded_since_sign=false
|
||||
jam_track_right.save!
|
||||
|
|
@ -59,11 +62,12 @@ module JamRuby
|
|||
|
||||
def copy_url_to_file(url, filename)
|
||||
uri = URI(url)
|
||||
open(filename, 'wb') do |io|
|
||||
open(filename, 'w+b') do |io|
|
||||
Net::HTTP.start(uri.host, uri.port) do |http|
|
||||
request = Net::HTTP::Get.new uri
|
||||
http.request request do |response|
|
||||
response_code = response.code.to_i
|
||||
puts "Response from server was #{response_code} / #{response.message}"
|
||||
unless response_code >= 200 && response_code <= 299
|
||||
raise "bad status code: #{response_code}. body: #{response.body}"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -712,6 +712,17 @@ module JamRuby
|
|||
)
|
||||
end
|
||||
|
||||
def jam_track_sign_complete(jam_track_right_id)
|
||||
signed = Jampb::JamTrackSignComplete.new()
|
||||
|
||||
Jampb::ClientMessage.new(
|
||||
:type => ClientMessage::Type::JAM_TRACK_SIGN_COMPLETE,
|
||||
:route_to => USER_TARGET_PREFIX + client_id,
|
||||
:jam_track_sign_complete => signed
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
def recording_master_mix_complete(receiver_id, recording_id, claimed_recording_id, band_id, msg, notification_id, created_at)
|
||||
recording_master_mix_complete = Jampb::RecordingMasterMixComplete.new(
|
||||
:recording_id => recording_id,
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ module JamRuby
|
|||
|
||||
# create storage directory that will house this jam_track, as well as
|
||||
def store_dir
|
||||
"jam_tracks/#{created_at.strftime('%m-%d-%Y')}/#{id}"
|
||||
"jam_tracks/#{id}"
|
||||
end
|
||||
|
||||
# create name of the file
|
||||
|
|
@ -66,34 +66,13 @@ module JamRuby
|
|||
s3_manager.sign_url(self[:url], {:expires => expiration_time, :response_content_type => 'audio/jka', :secure => false})
|
||||
end
|
||||
|
||||
|
||||
def can_download?(user)
|
||||
owners.include?(user)
|
||||
end
|
||||
|
||||
def self.index user, options = {}
|
||||
limit = options[:limit]
|
||||
limit ||= 20
|
||||
limit = limit.to_i
|
||||
|
||||
start = options[:start].presence
|
||||
start = start.to_i || 0
|
||||
|
||||
query = JamTrack.joins(:jam_track_tracks)
|
||||
.offset(start)
|
||||
.limit(limit)
|
||||
|
||||
query = query.where("jam_tracks.genre_id = '#{options[:genre]}'") unless options[:genre].blank?
|
||||
query = query.where("jam_track_tracks.instrument_id = '#{options[:instrument]}'") unless options[:instrument].blank?
|
||||
query = query.where("jam_tracks.sales_region = '#{options[:availability]}'") unless options[:availability].blank?
|
||||
query = query.group("jam_tracks.id")
|
||||
|
||||
if query.length == 0
|
||||
[query, nil]
|
||||
elsif query.length < limit
|
||||
[query, nil]
|
||||
else
|
||||
[query, start + limit]
|
||||
end
|
||||
def right_for_user(user)
|
||||
jam_track_rights.where("user_id=?", user).first
|
||||
end
|
||||
|
||||
def self.list_downloads(user, limit = 100, since = 0)
|
||||
|
|
@ -125,11 +104,6 @@ module JamRuby
|
|||
}
|
||||
end
|
||||
|
||||
def right_for_user(user)
|
||||
jam_track_rights.where("user_id=?", user).first
|
||||
end
|
||||
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ module JamRuby
|
|||
|
||||
validates_uniqueness_of :user_id, scope: :jam_track_id
|
||||
|
||||
|
||||
# Uploads the JKZ:
|
||||
mount_uploader :url, JamTrackRightUploader
|
||||
before_destroy :delete_s3_files
|
||||
|
|
@ -39,7 +38,6 @@ module JamRuby
|
|||
JamTrackRight.where("downloaded_since_sign=? AND updated_at <= ?", true, 5.minutes.ago).limit(1000)
|
||||
end
|
||||
|
||||
|
||||
# creates a short-lived URL that has access to the object.
|
||||
# the idea is that this is used when a user who has the rights to this tries to download this JamTrack
|
||||
# we would verify their rights (can_download?), and generates a URL in response to the click so that they can download
|
||||
|
|
@ -52,5 +50,24 @@ module JamRuby
|
|||
remove_url!
|
||||
end
|
||||
|
||||
def enqueue
|
||||
begin
|
||||
Resque.enqueue(JamTracksBuilder, self.id)
|
||||
rescue Exception => e
|
||||
# implies redis is down. we don't update started_at by bailing out here
|
||||
false
|
||||
end
|
||||
|
||||
# avoid db validations
|
||||
JamTrackRight.where(:id => self.id).update_all(:last_downloaded_at => Time.now)
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def update_download_count(count=1)
|
||||
self.download_count = self.download_count + count
|
||||
self.last_downloaded_at = Time.now
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ module JamRuby
|
|||
|
||||
mount_uploader :url, JamTrackTrackUploader
|
||||
|
||||
attr_accessible :track_type, :instrument, :instrument_id, :position, :part, :url, as: :admin
|
||||
attr_accessible :jam_track_id, :track_type, :instrument, :instrument_id, :position, :part, :url, as: :admin
|
||||
|
||||
validates :position, presence: true, numericality: {only_integer: true}, length: {in: 1..1000}
|
||||
validates :part, length: {maximum: 20}
|
||||
|
|
@ -36,6 +36,7 @@ module JamRuby
|
|||
# we would verify their rights (can_download?), and generates a URL in response to the click so that they can download
|
||||
# but the url is short lived enough so that it wouldn't be easily shared
|
||||
def sign_url(expiration_time = 120)
|
||||
puts "Signing: #{self[:url]}"
|
||||
s3_manager.sign_url(self[:url], {:expires => expiration_time, :response_content_type => 'audio/ogg', :secure => false})
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ module JamRuby
|
|||
belongs_to :band, :class_name => "JamRuby::Band", :foreign_key => "band_id"
|
||||
belongs_to :music_session, :class_name => "JamRuby::MusicSession", :foreign_key => "music_session_id"
|
||||
belongs_to :recording, :class_name => "JamRuby::Recording", :foreign_key => "recording_id"
|
||||
belongs_to :jam_track_right, :class_name => "JamRuby::JamTrackRight", :foreign_key => "jam_track_right_id"
|
||||
|
||||
validates :target_user, :presence => true
|
||||
validates :message, length: {minimum: 1, maximum: 400}, no_profanity: true, if: :text_message?
|
||||
|
|
@ -1186,6 +1187,11 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def send_jam_track_signed(jam_track_right)
|
||||
msg = @@message_factory.jam_track_signed(jam_track_right)
|
||||
@@mq_router.publish_to_all_clients(msg)
|
||||
end
|
||||
|
||||
def send_client_update(product, version, uri, size)
|
||||
msg = @@message_factory.client_update( product, version, uri, size)
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
require 'json'
|
||||
require 'resque'
|
||||
require 'resque-retry'
|
||||
require 'net/http'
|
||||
require 'digest/md5'
|
||||
|
||||
module JamRuby
|
||||
class JamTracksBuilder
|
||||
@queue = :jam_tracks_builder
|
||||
@@log = Logging.logger[JamTracksBuilder]
|
||||
attr_accessor :jam_track_right_id
|
||||
|
||||
def self.perform(jam_track_right_id)
|
||||
jam_track_builder = JamTracksBuilder.new()
|
||||
jam_track_builder.jam_track_right_id = jam_track_right_id
|
||||
jam_track_builder.run
|
||||
end
|
||||
|
||||
def run
|
||||
@@log.info("jam_track_builder job starting. jam_track_right_id #{jam_track_right_id}")
|
||||
@jam_track_right = JamTrackRight.find(jam_track_right_id)
|
||||
JamRuby::JamTracksManager.save_jam_track_right_jkz(@jam_track_right)
|
||||
puts "Signed jamtrack to #{@jam_track_right[:url]}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -64,12 +64,11 @@ describe JamTrackRight do
|
|||
it "should create" do
|
||||
ogg_path = File.join('spec', 'files', 'on.ogg')
|
||||
user = FactoryGirl.create(:user)
|
||||
#jam_track = FactoryGirl.create(:jam_track)
|
||||
jam_track_track = FactoryGirl.create(:jam_track_track)
|
||||
jam_track = jam_track_track.jam_track
|
||||
|
||||
uploader = JamTrackTrackUploader.new(jam_track_track, :url)
|
||||
uploader.store!(File.open(ogg_path))
|
||||
uploader.store!(File.open(ogg_path, 'rb'))
|
||||
jam_track_track.save!
|
||||
|
||||
jam_track_track[:url].should == jam_track_track.store_dir + '/' + jam_track_track.filename
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ class ApiJamTracksController < ApiController
|
|||
|
||||
# have to be signed in currently to see this screen
|
||||
before_filter :api_signed_in_user
|
||||
before_filter :lookup_jam_track, :only => [ :download ]
|
||||
|
||||
respond_to :json
|
||||
|
||||
|
|
@ -12,4 +13,30 @@ class ApiJamTracksController < ApiController
|
|||
render :json => { :message => "could not produce list of files" }, :status => 403
|
||||
end
|
||||
end
|
||||
|
||||
def download
|
||||
if @jam_track_right.valid?
|
||||
puts "Success"
|
||||
|
||||
if (@jam_track_right && @jam_track_right.signed && @jam_track_right.url.present? &&@jam_track_right.url.file.exists?)
|
||||
@jam_track_right.update_download_count
|
||||
@jam_track_right.save!
|
||||
redirect_to @jam_track_right.sign_url
|
||||
else
|
||||
@jam_track_right.enqueue
|
||||
render :json => { :message => "not available, digitally signing Jam Track offline." }, :status => 202
|
||||
end
|
||||
else
|
||||
puts "#@jam_track_right.errors: #{@jam_track_right.errors.inspect}"
|
||||
render :json => { :message => "download limit surpassed" }, :status => 403
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def lookup_jam_track
|
||||
@jam_track_right = JamTrackRight.where("jam_track_id=? AND user_id=?", params[:id], current_user).first
|
||||
puts "@jam_track_right: #{@jam_track_right.nil?}"
|
||||
raise PermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR unless @jam_track_right
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -191,6 +191,7 @@ SampleApp::Application.routes.draw do
|
|||
|
||||
# Jamtracks
|
||||
match '/jamtracks/downloads' => 'api_jam_tracks#list_downloads', :via => :get, :as => 'api_jam_tracks_list_downloads'
|
||||
match '/jamtracks/:id/download' => 'api_jam_tracks#download', :via => :get, :as => 'api_jam_tracks_download'
|
||||
|
||||
# Shopping carts
|
||||
match '/shopping_carts/add_jamtrack' => 'api_shopping_carts#add_jamtrack', :via => :post
|
||||
|
|
|
|||
|
|
@ -1,6 +1,17 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ApiJamTracksController do
|
||||
include CarrierWave::Test::Matchers
|
||||
|
||||
before(:all) do
|
||||
original_storage = JamTrackTrackUploader.storage = :fog
|
||||
original_storage = JamTrackRightUploader.storage = :fog
|
||||
end
|
||||
|
||||
after(:all) do
|
||||
JamTrackTrackUploader.storage = @original_storage
|
||||
JamTrackRightUploader.storage = @original_storage
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
@user = FactoryGirl.create(:user)
|
||||
|
|
@ -9,8 +20,6 @@ describe ApiJamTracksController do
|
|||
end
|
||||
|
||||
describe "download" do
|
||||
let(:mix) { FactoryGirl.create(:mix) }
|
||||
|
||||
it "list download" do
|
||||
right = JamTrackRight.create(:user=>@user, :jam_track=>@jam_track)
|
||||
get :list_downloads
|
||||
|
|
@ -19,4 +28,61 @@ describe ApiJamTracksController do
|
|||
json['downloads'].should have(1).items
|
||||
end
|
||||
end
|
||||
|
||||
describe "with a JamTrack" do
|
||||
before(:each) do
|
||||
JamTrackRight.destroy_all
|
||||
# Create a working JamTrack for these tests. The integrity
|
||||
# of this process is checked in other tests:
|
||||
@ogg_path = File.join('spec', 'files', 'on.ogg')
|
||||
@jam_track = FactoryGirl.create(:jam_track) #jam_track_track.jam_track
|
||||
jam_track_track = @jam_track.jam_track_tracks.first
|
||||
|
||||
uploader = JamTrackTrackUploader.new(jam_track_track, :url)
|
||||
uploader.store!(File.open(@ogg_path, 'rb'))
|
||||
#jam_track_track.url.store!(File.open(ogg_path, "rb"))
|
||||
jam_track_track.save!
|
||||
jam_track_track.reload
|
||||
ResqueSpec.reset!
|
||||
end
|
||||
|
||||
it "download depends on rights" do
|
||||
s3 = S3Manager.new(APP_CONFIG.aws_bucket, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
|
||||
get :download, :id => @jam_track.id
|
||||
response.status.should == 403
|
||||
|
||||
right = JamTrackRight.create(:user=>@user, :jam_track=>@jam_track)
|
||||
get :download, :id => @jam_track.id
|
||||
response.status.should == 202
|
||||
right.download_count.should eq(0)
|
||||
|
||||
JamTracksBuilder.should have_queued(right.id).in(:jam_tracks_builder)
|
||||
|
||||
qname = "#{ResqueSpec.queue_name(JamRuby::JamTracksBuilder)}"
|
||||
expect(ResqueSpec.peek(qname).present?).to eq(true)
|
||||
ResqueSpec.perform_next(qname)
|
||||
|
||||
JamTracksBuilder.should_not have_queued(right.id).in(:jam_tracks_builder)
|
||||
right.reload
|
||||
right.download_count.should eq(0)
|
||||
|
||||
get :download, :id => @jam_track.id
|
||||
response.status.should == 302
|
||||
response.location.should =~ /.*#{Regexp.escape(right.filename)}.*/
|
||||
#response.should redirect_to(/.*#{Regexp.escape(right.filename)}.*/)
|
||||
#response.should redirect_to("%r{.*#{Regexp.escape(right.filename)}.*}")
|
||||
|
||||
#right.reload
|
||||
#s3.exists?(response.location).should be_true
|
||||
#puts "s3.length (response.location): #{s3.length (response.location)}"
|
||||
#s3.length (response.location).should > File.size?(@ogg_path)
|
||||
|
||||
right.reload
|
||||
right.download_count.should eq(1)
|
||||
|
||||
notifications = Notification.where(:jam_track_right_id => right.id)
|
||||
notifications.count.should == 1
|
||||
puts "notifications.first.inspect: #{notifications.first.inspect}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue