Merge branch 'develop' of bitbucket.org:jamkazam/jam-cloud into develop
This commit is contained in:
commit
7ab6d4d1fb
|
|
@ -117,4 +117,4 @@ end
|
|||
gem 'pry'
|
||||
gem 'pry-remote'
|
||||
gem 'pry-stack_explorer'
|
||||
gem 'pry-debugger'
|
||||
#gem 'pry-debugger'
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ ActiveAdmin.register JamRuby::Connection, :as => 'Connection' do
|
|||
row :locidispid
|
||||
row :aasm_state
|
||||
row :udp_reachable
|
||||
row :is_network_testing
|
||||
row :scoring_failures
|
||||
row :scoring_timeout_occurrences
|
||||
row :scoring_failures_offset
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ ActiveAdmin.register_page "Current Scoring Load" do
|
|||
table_for GetWork.summary do
|
||||
column "Work", :work_count
|
||||
column "Who", Proc.new { |connection| "#{connection.first_name} #{connection.last_name} - #{connection.email}" }
|
||||
column "Errors", Proc.new { |connection| "#{connection.udp_reachable != false ? "" : "No STUN,"} #{connection.in_timeout != 'f' ? "Timeout," : ""} #{connection.in_session != 'f' ? "In-Session," : ""}" }
|
||||
column "Errors", Proc.new { |connection| "#{connection.udp_reachable != false ? "" : "No STUN,"} #{connection.is_network_testing != false ? "NETWORK TESTING" : ""} #{connection.in_timeout != 'f' ? "Timeout," : ""} #{connection.in_session != 'f' ? "In-Session," : ""}" }
|
||||
column "Total Timeouts", :scoring_timeout_occurrences
|
||||
column "Current Scoring Failures", :scoring_failures
|
||||
column "Offset", :scoring_failures_offset
|
||||
|
|
|
|||
|
|
@ -216,4 +216,7 @@ fix_find_session_sorting_2216c.sql
|
|||
entabulate_current_network_scores.sql
|
||||
discard_scores_changed.sql
|
||||
emails_from_update.sql
|
||||
|
||||
add_active_feed.sql
|
||||
connection_network_testing.sql
|
||||
video_sources.sql
|
||||
recorded_videos.sql
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
alter table feeds add column active BOOLEAN DEFAULT FALSE;
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
-- let the server know if the client is network testing. If so, then also remove them from work
|
||||
ALTER TABLE connections ADD COLUMN is_network_testing BOOLEAN DEFAULT FALSE NOT NULL;
|
||||
|
||||
DROP FUNCTION IF EXISTS get_work (my_client_id VARCHAR(64), mylocidispid BIGINT, myaddr BIGINT, return_rows INT, stale_score INTERVAL);
|
||||
CREATE FUNCTION get_work (my_client_id VARCHAR(64), mylocidispid BIGINT, myaddr BIGINT, return_rows INT, stale_score INTERVAL) RETURNS TABLE (client_id VARCHAR(64)) VOLATILE AS $$
|
||||
BEGIN
|
||||
RETURN QUERY WITH
|
||||
scorable_locations AS (
|
||||
SELECT DISTINCT locidispid FROM connections WHERE client_type = 'client' AND connections.client_id != my_client_id AND addr != myaddr AND udp_reachable AND is_network_testing = FALSE AND NOW() > scoring_timeout AND connections.music_session_id IS NULL AND
|
||||
locidispid NOT IN (SELECT DISTINCT blocidispid FROM most_recent_scores WHERE alocidispid = mylocidispid AND (current_timestamp - score_dt) < stale_score) AND
|
||||
locidispid/1000000 IN (SELECT locid FROM geoiplocations WHERE geog && st_buffer((SELECT geog FROM geoiplocations WHERE locid = mylocidispid/1000000), 4023360))
|
||||
)
|
||||
|
||||
SELECT tmp.client_id FROM (SELECT connections.client_id, random() AS r, row_number() OVER (PARTITION BY connections.locidispid) AS rownum FROM connections, scorable_locations
|
||||
WHERE connections.locidispid = scorable_locations.locidispid AND client_type = 'client' AND connections.client_id != my_client_id AND addr != myaddr AND udp_reachable AND NOW() > scoring_timeout AND connections.music_session_id IS NULL ) tmp WHERE rownum <= 1 ORDER BY r LIMIT return_rows;
|
||||
|
||||
RETURN;
|
||||
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
|
||||
DROP FUNCTION IF EXISTS get_work_summary (stale_score INTERVAL);
|
||||
CREATE FUNCTION get_work_summary (stale_score INTERVAL) RETURNS TABLE (work_count BIGINT, client_id VARCHAR(64), email VARCHAR, first_name VARCHAR, last_name VARCHAR, user_id VARCHAR(64), udp_reachable BOOLEAN, in_timeout BOOLEAN, in_session BOOLEAN, scoring_failures INT, scoring_failures_offset INT, scoring_timeout_occurrences INT, is_network_testing BOOLEAN) VOLATILE AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
SELECT SUM(CASE WHEN tmp.test_client_id IS NULL OR tmp.in_session OR tmp.in_timeout OR tmp.udp_reachable = FALSE OR tmp.is_network_testing = TRUE THEN 0 ELSE 1 END) AS work_count, tmp.client_id AS client_id, users.email, users.first_name, users.last_name, users.id AS user_id, tmp.udp_reachable, tmp.in_timeout, tmp.in_session, tmp.scoring_failures, tmp.scoring_failures_offset, tmp.scoring_timeout_occurrences, tmp.is_network_testing FROM
|
||||
(SELECT connections.client_type, scorable_locations.client_id AS test_client_id, connections.client_id AS client_id, connections.user_id AS user_id, connections.udp_reachable, connections.scoring_timeout > NOW() as in_timeout, connections.music_session_id IS NOT NULL AS in_session, connections.scoring_failures, connections.scoring_failures_offset, connections.scoring_timeout_occurrences, connections.is_network_testing, scorable_locations.client_id IS NULL AS same_client, row_number() OVER (PARTITION BY connections.locidispid) AS rownum FROM connections LEFT OUTER JOIN scorable_locations(connections.client_id, connections.locidispid, connections.addr, stale_score)
|
||||
ON connections.locidispid != scorable_locations.locidispid) tmp INNER JOIN users ON tmp.user_id = users.id WHERE tmp.client_type = 'client' GROUP BY tmp.client_id, users.email, users.first_name, users.last_name, users.id, tmp.same_client, tmp.udp_reachable, tmp.in_timeout, tmp.in_session, tmp.scoring_failures, tmp.scoring_failures_offset, tmp.scoring_timeout_occurrences, tmp.is_network_testing ORDER BY work_count DESC;
|
||||
RETURN;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
DROP FUNCTION IF EXISTS get_work_summary_no_agg(stale_score INTERVAL);
|
||||
-- useful for debugging get_work_summary
|
||||
CREATE FUNCTION get_work_summary_no_agg (stale_score INTERVAL) RETURNS TABLE (client_id VARCHAR(64), test_client_id VARCHAR(64), email VARCHAR, first_name VARCHAR, last_name VARCHAR, user_id VARCHAR(64), udp_reachable BOOLEAN, in_timeout BOOLEAN, scoring_failures INT, scoring_failures_offset INT, scoring_timeout_occurrences INT, is_network_testing BOOLEAN) VOLATILE AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
SELECT tmp.client_id AS client_id, tmp.test_client_id, users.email, users.first_name, users.last_name, users.id AS user_id, tmp.udp_reachable, tmp.in_timeout, tmp.scoring_failures, tmp.scoring_failures_offset, tmp.scoring_timeout_occurrences, tmp.is_network_testing FROM
|
||||
(SELECT scorable_locations.client_id AS test_client_id, connections.client_id AS client_id, connections.user_id AS user_id, connections.udp_reachable, connections.scoring_timeout > NOW() as in_timeout, connections.scoring_failures, connections.scoring_failures_offset, connections.scoring_timeout_occurrences, connections.is_network_testing, scorable_locations.client_id IS NULL AS same_client, row_number() OVER (PARTITION BY connections.locidispid) AS rownum FROM connections LEFT OUTER JOIN scorable_locations(connections.client_id, connections.locidispid, connections.addr, stale_score)
|
||||
ON connections.locidispid != scorable_locations.locidispid AND connections.client_type = 'client') tmp INNER JOIN users ON tmp.user_id = users.id ORDER BY tmp.client_id;
|
||||
RETURN;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
CREATE TABLE recorded_videos (
|
||||
id BIGINT PRIMARY KEY,
|
||||
user_id VARCHAR(64) REFERENCES users(id) ON DELETE CASCADE,
|
||||
fully_uploaded BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
recording_id VARCHAR(64) NOT NULL,
|
||||
length BIGINT,
|
||||
client_video_source_id VARCHAR(64) NOT NULL,
|
||||
url VARCHAR(1024),
|
||||
file_offset BIGINT,
|
||||
upload_failures INTEGER NOT NULL DEFAULT 0,
|
||||
discard BOOLEAN,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
ALTER TABLE recorded_videos ALTER COLUMN id SET DEFAULT nextval('tracks_next_tracker_seq');
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
CREATE TABLE video_sources (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
connection_id VARCHAR(64) NOT NULL,
|
||||
client_video_source_id VARCHAR(64) NOT NULL,
|
||||
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ gem 'sendgrid', '1.2.0'
|
|||
gem 'aws-sdk' #, '1.29.1'
|
||||
gem 'carrierwave', '0.9.0'
|
||||
gem 'aasm', '3.0.16'
|
||||
gem 'devise', '>= 1.1.2'
|
||||
gem 'devise', '3.3.0' # 3.4.0 causes: uninitialized constant ActionController::Metal (NameError)
|
||||
gem 'postgres-copy'
|
||||
gem 'geokit'
|
||||
gem 'geokit-rails'
|
||||
|
|
|
|||
|
|
@ -173,6 +173,8 @@ require "jam_ruby/models/chat_message"
|
|||
require "jam_ruby/models/generic_state"
|
||||
require "jam_ruby/models/score_history"
|
||||
require "jam_ruby/models/jam_company"
|
||||
require "jam_ruby/models/video_source"
|
||||
require "jam_ruby/models/recorded_video"
|
||||
|
||||
include Jampb
|
||||
|
||||
|
|
|
|||
|
|
@ -412,26 +412,28 @@
|
|||
end
|
||||
end
|
||||
|
||||
def scheduled_session_comment(user, msg, comment, session)
|
||||
return if !user.subscribe_email
|
||||
def scheduled_session_comment(target_user, sender, msg, comment, session)
|
||||
return if !target_user.subscribe_email
|
||||
|
||||
email = user.email
|
||||
email = target_user.email
|
||||
subject = "New Session Comment"
|
||||
unique_args = {:type => "scheduled_session_comment"}
|
||||
@body = msg
|
||||
@session_name = session.name
|
||||
@session_date = session.pretty_scheduled_start(true)
|
||||
@comment = comment
|
||||
@sender = sender
|
||||
@suppress_user_has_account_footer = true
|
||||
@session_url = "#{APP_CONFIG.external_root_url}/sessions/#{session.id}/details"
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
|
||||
sendgrid_recipients([email])
|
||||
sendgrid_substitute('@USERID', [user.id])
|
||||
sendgrid_substitute('@USERID', [target_user.id])
|
||||
|
||||
mail(:to => email, :subject => subject) do |format|
|
||||
format.text
|
||||
format.html
|
||||
format.html { render :layout => "from_user_mailer" }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
<% provide(:title, 'Scheduled Session Comment') %>
|
||||
<% provide(:title, "Scheduled Session Comment from #{@sender.name}") %>
|
||||
<% provide(:photo_url, @sender.resolved_photo_url) %>
|
||||
|
||||
<p><%= @body %></p>
|
||||
<% content_for :note do %>
|
||||
<p><%= @comment %></p>
|
||||
|
||||
<p><%= @comment %></p>
|
||||
<p><%= @session_name %></p>
|
||||
<p><%= @session_date %></p>
|
||||
|
||||
<p><a style="color: #588C98;" href="<%= @session_url %>">View Session Details</a></p>
|
||||
<p><a style="color: #588C98;" href="<%= @session_url %>">View Session Details</a></p>
|
||||
<% end %>
|
||||
|
|
@ -5,4 +5,6 @@
|
|||
|
||||
<%= @comment %>
|
||||
|
||||
- <%= @sender.name %>
|
||||
|
||||
See session details at <%= @session_url %>.
|
||||
|
|
@ -89,7 +89,7 @@ module JamRuby
|
|||
udp_reachable_value = udp_reachable.nil? ? 'udp_reachable' : udp_reachable
|
||||
|
||||
sql =<<SQL
|
||||
UPDATE connections SET (channel_id, aasm_state, updated_at, music_session_id, joined_session_at, stale_time, expire_time, udp_reachable, gateway) = ('#{channel_id}', '#{Connection::CONNECT_STATE.to_s}', NOW(), #{music_session_id_expression}, #{joined_session_at_expression}, #{connection_stale_time}, #{connection_expire_time}, #{udp_reachable_value}, '#{gateway}')
|
||||
UPDATE connections SET (channel_id, aasm_state, updated_at, music_session_id, joined_session_at, stale_time, expire_time, udp_reachable, gateway, is_network_testing) = ('#{channel_id}', '#{Connection::CONNECT_STATE.to_s}', NOW(), #{music_session_id_expression}, #{joined_session_at_expression}, #{connection_stale_time}, #{connection_expire_time}, #{udp_reachable_value}, '#{gateway}', FALSE)
|
||||
WHERE
|
||||
client_id = '#{conn.client_id}'
|
||||
RETURNING music_session_id
|
||||
|
|
@ -321,7 +321,7 @@ SQL
|
|||
end
|
||||
end
|
||||
|
||||
def join_music_session(user, client_id, music_session, as_musician, tracks, audio_latency)
|
||||
def join_music_session(user, client_id, music_session, as_musician, tracks, audio_latency, video_sources=nil)
|
||||
connection = nil
|
||||
|
||||
ConnectionManager.active_record_transaction do |connection_manager|
|
||||
|
|
@ -329,7 +329,7 @@ SQL
|
|||
|
||||
connection = Connection.find_by_client_id_and_user_id!(client_id, user.id)
|
||||
|
||||
connection.join_the_session(music_session, as_musician, tracks, user, audio_latency)
|
||||
connection.join_the_session(music_session, as_musician, tracks, user, audio_latency, video_sources)
|
||||
# connection.music_session_id = music_session.id
|
||||
# connection.as_musician = as_musician
|
||||
# connection.joining_session = true
|
||||
|
|
|
|||
|
|
@ -47,6 +47,11 @@ module JamRuby
|
|||
end
|
||||
|
||||
def before_destroy
|
||||
feed = Feed.find_by_music_session_id(self.id)
|
||||
unless feed.nil?
|
||||
feed.active = false
|
||||
feed.save
|
||||
end
|
||||
self.mount.destroy if self.mount
|
||||
end
|
||||
|
||||
|
|
@ -447,7 +452,7 @@ module JamRuby
|
|||
[music_sessions, user_scores]
|
||||
end
|
||||
|
||||
def self.participant_create user, music_session_id, client_id, as_musician, tracks, audio_latency
|
||||
def self.participant_create(user, music_session_id, client_id, as_musician, tracks, audio_latency, video_sources=nil)
|
||||
music_session = MusicSession.find(music_session_id)
|
||||
|
||||
if music_session.active_music_session
|
||||
|
|
@ -458,7 +463,7 @@ module JamRuby
|
|||
|
||||
active_music_session.with_lock do # VRFS-1297
|
||||
active_music_session.tick_track_changes
|
||||
connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, audio_latency)
|
||||
connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, audio_latency, video_sources)
|
||||
|
||||
if connection.errors.any?
|
||||
# rollback the transaction to make sure nothing is disturbed in the database
|
||||
|
|
@ -515,7 +520,7 @@ module JamRuby
|
|||
|
||||
# auto-join this user into the newly created session
|
||||
as_musician = true
|
||||
connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, audio_latency)
|
||||
connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, audio_latency, video_sources)
|
||||
|
||||
unless connection.errors.any?
|
||||
user.update_progression_field(:first_music_session_at)
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@ module JamRuby
|
|||
belongs_to :music_session, :class_name => "JamRuby::ActiveMusicSession", foreign_key: :music_session_id
|
||||
has_one :latency_tester, class_name: 'JamRuby::LatencyTester', foreign_key: :client_id, primary_key: :client_id
|
||||
has_many :tracks, :class_name => "JamRuby::Track", :inverse_of => :connection, :foreign_key => 'connection_id', :dependent => :delete_all
|
||||
has_many :video_sources, :class_name => "JamRuby::VideoSource", :inverse_of => :connection, :foreign_key => 'connection_id', :dependent => :delete_all
|
||||
|
||||
validates :as_musician, :inclusion => {:in => [true, false]}
|
||||
validates :as_musician, :inclusion => {:in => [true, false, nil]}
|
||||
validates :client_type, :inclusion => {:in => [TYPE_CLIENT, TYPE_BROWSER, TYPE_LATENCY_TESTER]}
|
||||
validates_numericality_of :last_jam_audio_latency, greater_than:0, :allow_nil => true
|
||||
validate :can_join_music_session, :if => :joining_session?
|
||||
|
|
@ -162,12 +163,13 @@ module JamRuby
|
|||
true
|
||||
end
|
||||
|
||||
def join_the_session(music_session, as_musician, tracks, user, audio_latency)
|
||||
def join_the_session(music_session, as_musician, tracks, user, audio_latency, videos=nil)
|
||||
self.music_session_id = music_session.id
|
||||
self.as_musician = as_musician
|
||||
self.joining_session = true
|
||||
self.joined_session_at = Time.now
|
||||
associate_tracks(tracks) unless tracks.nil?
|
||||
associate_videos(videos) unless videos.nil?
|
||||
self.save
|
||||
|
||||
# if user joins the session as a musician, update their addr and location
|
||||
|
|
@ -192,6 +194,19 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def associate_videos(videos)
|
||||
unless videos.nil?
|
||||
self.video_sources.clear()
|
||||
videos.each do |video|
|
||||
v = VideoSource.new
|
||||
v.connection = self
|
||||
v.client_video_source_id = video["client_video_source_id"]
|
||||
v.save # todo what if it fails?
|
||||
self.video_sources << v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.update_locidispids(use_copied = true)
|
||||
# using addr, we can rebuild locidispid
|
||||
|
||||
|
|
|
|||
|
|
@ -47,13 +47,13 @@ module JamRuby
|
|||
# handle sort
|
||||
if sort == 'date'
|
||||
query = query.where("feeds.id < #{start}")
|
||||
query = query.order('feeds.id DESC')
|
||||
query = query.order('feeds.active DESC, feeds.id DESC')
|
||||
elsif sort == 'plays'
|
||||
query = query.offset(start)
|
||||
query = query.order("COALESCE(recordings.play_count, music_sessions.play_count) DESC ")
|
||||
query = query.order("feeds.active DESC, COALESCE(recordings.play_count, music_sessions.play_count) DESC")
|
||||
elsif sort == 'likes'
|
||||
query = query.offset(start)
|
||||
query = query.order("COALESCE(recordings.like_count, music_sessions.like_count) DESC ")
|
||||
query = query.order("feeds.active DESC, COALESCE(recordings.like_count, music_sessions.like_count) DESC")
|
||||
else
|
||||
raise "sort not implemented: #{sort}"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ module JamRuby
|
|||
|
||||
def self.get_work_list(connection, rows = 25, staleness_hours = 120)
|
||||
|
||||
return [] if connection.is_network_testing # short-circuit 0 results if is_network_testing
|
||||
return [] unless connection.udp_reachable # short-circuit 0 results if udp_reachable
|
||||
return [] if connection.scoring_timeout > Time.now # short-circuit 0 results if in scoring timeout
|
||||
return [] if connection.in_session?
|
||||
|
|
@ -25,7 +26,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def self.summary(staleness_hours = 120)
|
||||
r = GetWork.select([:work_count, :client_id, :email, :first_name, :last_name, :user_id, :udp_reachable, :in_timeout, :in_session, :scoring_failures, :scoring_failures_offset, :scoring_timeout_occurrences]).find_by_sql("select work_count, client_id, email, first_name, last_name, user_id, udp_reachable, in_timeout, in_session, scoring_failures, scoring_failures_offset, scoring_timeout_occurrences FROM get_work_summary(INTERVAL '#{staleness_hours} hours')" )
|
||||
r = GetWork.select([:work_count, :client_id, :email, :first_name, :last_name, :user_id, :udp_reachable, :in_timeout, :in_session, :scoring_failures, :scoring_failures_offset, :scoring_timeout_occurrences, :is_network_testing]).find_by_sql("select work_count, client_id, email, first_name, last_name, user_id, udp_reachable, in_timeout, in_session, scoring_failures, scoring_failures_offset, scoring_timeout_occurrences, is_network_testing FROM get_work_summary(INTERVAL '#{staleness_hours} hours')" )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ module JamRuby
|
|||
def add_to_feed
|
||||
feed = Feed.new
|
||||
feed.music_session = self
|
||||
feed.active = true
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -604,6 +605,12 @@ module JamRuby
|
|||
|
||||
hist.end_history if hist
|
||||
|
||||
feed = Feed.find_by_music_session_id(session_id)
|
||||
unless feed.nil?
|
||||
feed.active = false
|
||||
feed.save
|
||||
end
|
||||
|
||||
Notification.send_session_ended(session_id)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -930,14 +930,13 @@ module JamRuby
|
|||
rsvp_requests = RsvpRequest.index(music_session)
|
||||
target_users = send_to_cancelled ? rsvp_requests.map { |r| r.user } : rsvp_requests.where(:canceled => false).map { |r| r.user }
|
||||
target_users = target_users.concat([music_session.creator])
|
||||
source_user = creator
|
||||
pending_invites = music_session.pending_invitations
|
||||
|
||||
# remove the creator from the array
|
||||
target_users = target_users.concat(pending_invites).uniq - [creator]
|
||||
|
||||
target_users.each do |target_user|
|
||||
source_user = creator
|
||||
|
||||
notification = Notification.new
|
||||
notification.description = NotificationTypes::SCHEDULED_SESSION_COMMENT
|
||||
notification.source_user_id = source_user.id
|
||||
|
|
@ -964,7 +963,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
begin
|
||||
UserMailer.scheduled_session_comment(target_user, notification_msg, comment, music_session).deliver
|
||||
UserMailer.scheduled_session_comment(target_user, source_user, notification_msg, comment, music_session).deliver
|
||||
rescue => e
|
||||
@@log.error("Unable to send SCHEDULED_SESSION_COMMENT email to user #{target_user.email} #{e}")
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
module JamRuby
|
||||
# Video analog to JamRuby::RecordedTrack
|
||||
class RecordedVideo < ActiveRecord::Base
|
||||
belongs_to :user, :class_name => "JamRuby::User", :inverse_of => :recorded_videos
|
||||
belongs_to :recording, :class_name => "JamRuby::Recording", :inverse_of => :recorded_videos
|
||||
|
||||
validates :client_video_source_id, :presence => true
|
||||
|
||||
def self.create_from_video_source(video_source, recording)
|
||||
recorded_video_source = self.new
|
||||
recorded_video_source.recording = recording
|
||||
recorded_video_source.client_video_source_id = video_source.id
|
||||
recorded_video_source.user = video_source.connection.user
|
||||
recorded_video_source.save
|
||||
recorded_video_source
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -9,6 +9,7 @@ module JamRuby
|
|||
has_many :claimed_recordings, :class_name => "JamRuby::ClaimedRecording", :inverse_of => :recording, :foreign_key => 'recording_id', :dependent => :destroy
|
||||
has_many :mixes, :class_name => "JamRuby::Mix", :inverse_of => :recording, :foreign_key => 'recording_id', :dependent => :destroy
|
||||
has_many :recorded_tracks, :class_name => "JamRuby::RecordedTrack", :foreign_key => :recording_id, :dependent => :destroy
|
||||
has_many :recorded_videos, :class_name => "JamRuby::RecordedVideo", :foreign_key => :recording_id, :dependent => :destroy
|
||||
has_many :comments, :class_name => "JamRuby::RecordingComment", :foreign_key => "recording_id", :dependent => :destroy
|
||||
has_many :likes, :class_name => "JamRuby::RecordingLiker", :foreign_key => "recording_id", :dependent => :destroy
|
||||
has_many :plays, :class_name => "JamRuby::PlayablePlay", :as => :playable, :dependent => :destroy
|
||||
|
|
@ -152,6 +153,10 @@ module JamRuby
|
|||
connection.tracks.each do |track|
|
||||
recording.recorded_tracks << RecordedTrack.create_from_track(track, recording)
|
||||
end
|
||||
|
||||
connection.video_sources.each do |video|
|
||||
recording.recorded_videos << RecordedVideo.create_from_video_source(video, recording)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -298,22 +303,82 @@ module JamRuby
|
|||
since = 0 unless since || since == '' # guard against nil
|
||||
|
||||
uploads = []
|
||||
RecordedTrack
|
||||
.joins(:recording)
|
||||
.where(:user_id => user.id)
|
||||
.where(:fully_uploaded => false)
|
||||
.where('recorded_tracks.id > ?', since)
|
||||
.where("upload_failures <= #{APP_CONFIG.max_track_upload_failures}")
|
||||
.where("duration IS NOT NULL")
|
||||
.where('all_discarded = false')
|
||||
.order('recorded_tracks.id')
|
||||
.limit(limit).each do |recorded_track|
|
||||
uploads.push({
|
||||
:type => "recorded_track",
|
||||
:client_track_id => recorded_track.client_track_id,
|
||||
:recording_id => recorded_track.recording_id,
|
||||
:next => recorded_track.id
|
||||
})
|
||||
|
||||
# Uploads now include videos in addition to the tracks.
|
||||
# This is accomplished using a SQL union via arel, as follows:
|
||||
|
||||
# Select fields from track. Note the reorder, which removes
|
||||
# the default scope sort as it b0rks the union. Also note the
|
||||
# alias so that we can differentiate tracks and videos when
|
||||
# processing the results:
|
||||
track_arel = RecordedTrack.select([
|
||||
:id,
|
||||
:recording_id,
|
||||
:url,
|
||||
:fully_uploaded,
|
||||
:upload_failures,
|
||||
:client_track_id,
|
||||
Arel::Nodes::As.new('track', Arel.sql('item_type'))
|
||||
]).reorder("")
|
||||
|
||||
# Select fields for video. Note that it must include
|
||||
# the same number of fields as the track in order for
|
||||
# the union to work:
|
||||
vid_arel = RecordedVideo.select([
|
||||
:id,
|
||||
:recording_id,
|
||||
:url,
|
||||
:fully_uploaded,
|
||||
:upload_failures,
|
||||
:client_video_source_id,
|
||||
Arel::Nodes::As.new('video', Arel.sql('item_type'))
|
||||
]).reorder("")
|
||||
|
||||
# Glue them together:
|
||||
union = track_arel.union(vid_arel)
|
||||
|
||||
# Create a table alias from the union so we can get back to arel:
|
||||
utable = RecordedTrack.arel_table.create_table_alias(union, :recorded_items)
|
||||
arel = track_arel.from(utable)
|
||||
arel = arel.select([
|
||||
:id,
|
||||
:recording_id,
|
||||
:url,
|
||||
:fully_uploaded,
|
||||
:upload_failures,
|
||||
:client_track_id,
|
||||
:item_type
|
||||
])
|
||||
|
||||
# Further joining and criteria for the unioned object:
|
||||
arel = arel.joins("INNER JOIN (SELECT id as rec_id, all_discarded, duration FROM recordings) recs ON rec_id=recorded_items.recording_id") \
|
||||
.where('recorded_items.fully_uploaded =?', false) \
|
||||
.where('recorded_items.id > ?', since) \
|
||||
.where("upload_failures <= #{APP_CONFIG.max_track_upload_failures}") \
|
||||
.where("duration IS NOT NULL") \
|
||||
.where('all_discarded = false') \
|
||||
.order('recorded_items.id') \
|
||||
.limit(limit)
|
||||
|
||||
# Load into array:
|
||||
arel.each do |recorded_item|
|
||||
if(recorded_item.item_type=='video')
|
||||
# A video:
|
||||
uploads << ({
|
||||
:type => "recorded_video",
|
||||
:client_video_source_id => recorded_item.client_track_id,
|
||||
:recording_id => recorded_item.recording_id,
|
||||
:next => recorded_item.id
|
||||
})
|
||||
else
|
||||
# A track:
|
||||
uploads << ({
|
||||
:type => "recorded_track",
|
||||
:client_track_id => recorded_item.client_track_id,
|
||||
:recording_id => recorded_item.recording_id,
|
||||
:next => recorded_item.id
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
next_value = uploads.length > 0 ? uploads[-1][:next].to_s : nil
|
||||
|
|
@ -321,7 +386,6 @@ module JamRuby
|
|||
next_value = since # echo back to the client the same value they passed in, if there are no results
|
||||
end
|
||||
|
||||
|
||||
{
|
||||
"uploads" => uploads,
|
||||
"next" => next_value.to_s
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
if rsvp_slot.chosen && r[:accept]
|
||||
raise StateError, "The #{rsvp_slot.instrument_id} slot has already been approved for another user."
|
||||
raise StateError, "All RSVP slots for the #{rsvp_slot.instrument_id} have been already approved."
|
||||
end
|
||||
|
||||
if r[:accept]
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ module JamRuby
|
|||
|
||||
# saved tracks
|
||||
has_many :recorded_tracks, :foreign_key => "user_id", :class_name => "JamRuby::RecordedTrack", :inverse_of => :user
|
||||
has_many :recorded_videos, :foreign_key => "user_id", :class_name => "JamRuby::RecordedVideo", :inverse_of => :user
|
||||
|
||||
# invited users
|
||||
has_many :invited_users, :foreign_key => "sender_id", :class_name => "JamRuby::InvitedUser"
|
||||
|
|
@ -1271,8 +1272,7 @@ module JamRuby
|
|||
if audio_latency > 2
|
||||
# updating the connection is best effort
|
||||
if connection
|
||||
connection.last_jam_audio_latency = audio_latency
|
||||
connection.save
|
||||
Connection.where(:id => connection.id).update_all(:last_jam_audio_latency => audio_latency)
|
||||
end
|
||||
|
||||
self.last_jam_audio_latency = audio_latency
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
module JamRuby
|
||||
# Video analog to JamRuby::Track
|
||||
class VideoSource < ActiveRecord::Base
|
||||
self.table_name = "video_sources"
|
||||
self.primary_key = 'id'
|
||||
default_scope order('created_at ASC')
|
||||
belongs_to :connection, :class_name => "JamRuby::Connection", :inverse_of => :video_sources, :foreign_key => 'connection_id'
|
||||
validates :connection, presence: true
|
||||
end
|
||||
end
|
||||
|
|
@ -38,6 +38,7 @@ module JamRuby
|
|||
|
||||
stale_sessions.each do |s|
|
||||
if s.connections.count == 0
|
||||
s.before_destroy
|
||||
s.delete
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -231,6 +231,10 @@ FactoryGirl.define do
|
|||
sequence(:client_track_id) { |n| "client_track_id#{n}"}
|
||||
end
|
||||
|
||||
factory :video_source, :class => JamRuby::VideoSource do
|
||||
client_video_source_id "test_source_id"
|
||||
end
|
||||
|
||||
factory :recorded_track, :class => JamRuby::RecordedTrack do
|
||||
instrument JamRuby::Instrument.first
|
||||
sound 'stereo'
|
||||
|
|
@ -244,6 +248,12 @@ FactoryGirl.define do
|
|||
association :recording, factory: :recording
|
||||
end
|
||||
|
||||
factory :recorded_video, :class => JamRuby::RecordedVideo do
|
||||
sequence(:client_id) { |n| "client_id-#{n}"}
|
||||
sequence(:track_id) { |n| "track_id-#{n}"}
|
||||
sequence(:client_track_id) { |n| "client_track_id-#{n}"}
|
||||
end
|
||||
|
||||
factory :instrument, :class => JamRuby::Instrument do
|
||||
description { |n| "Instrument #{n}" }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -711,5 +711,38 @@ describe ActiveMusicSession do
|
|||
@music_session.get_connection_ids(exclude_client_id: @connection2.client_id, as_musician: true).should == [@connection1.client_id]
|
||||
end
|
||||
end
|
||||
|
||||
describe "join_the_session" do
|
||||
let(:creator_1) { FactoryGirl.create(:user, last_jam_locidispid: 4, last_jam_audio_latency: 8) }
|
||||
let(:creator_conn_1) { FactoryGirl.create(:connection, user: creator_1, ip_address: '4.4.4.4', locidispid: 4, addr:4) }
|
||||
let!(:music_session_1) { FactoryGirl.create(:active_music_session, :creator => creator_1, genre: Genre.find('african'), language: 'eng', description: "Bunny Jumps" ) }
|
||||
let(:tracks) { [{'sound' => 'mono', 'client_track_id' => 'abc', 'instrument_id' => 'piano'}] }
|
||||
let(:videos) { [{'client_video_source_id' => 'abc'}] }
|
||||
|
||||
it "joins the session with no video" do
|
||||
creator_conn_1.join_the_session(music_session_1.music_session, true, tracks, creator_1, 10)
|
||||
creator_conn_1.errors.any?.should be_false
|
||||
|
||||
music_sessions = ActiveMusicSession.index(creator_1)
|
||||
music_sessions.should_not be_nil
|
||||
music_sessions.length.should == 1
|
||||
music_sessions[0].connections.should have(1).items
|
||||
music_sessions[0].connections.should have(1).items
|
||||
music_sessions[0].connections[0].tracks.should have(1).items
|
||||
music_sessions[0].connections[0].video_sources.should have(0).items
|
||||
end
|
||||
|
||||
it "joins the session with video" do
|
||||
creator_conn_1.join_the_session(music_session_1.music_session, true, tracks, creator_1, 10, videos)
|
||||
creator_conn_1.errors.any?.should be_false
|
||||
music_sessions = ActiveMusicSession.index(creator_1)
|
||||
music_sessions.should_not be_nil
|
||||
music_sessions.length.should == 1
|
||||
creator_conn_1.video_sources.should have(1).items
|
||||
music_sessions[0].connections.should have(1).items
|
||||
music_sessions[0].connections[0].video_sources.should have(1).items
|
||||
music_sessions[0].connections[0].tracks.should have(1).items
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ describe JamRuby::Connection do
|
|||
:ip_address => "1.1.1.1",
|
||||
:client_id => "1") }
|
||||
|
||||
let(:tracks) { [{'sound' => 'mono', 'client_track_id' => 'abc', 'instrument_id' => 'piano'}] }
|
||||
|
||||
it 'starts in the correct state' do
|
||||
connection = FactoryGirl.create(:connection,
|
||||
:user => user,
|
||||
|
|
@ -100,4 +102,5 @@ describe JamRuby::Connection do
|
|||
conn.locidispid.should == 0
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -54,16 +54,16 @@ describe Feed do
|
|||
end
|
||||
|
||||
describe "sorting" do
|
||||
it "sorts by index (date) DESC" do
|
||||
it "sorts by active flag / index (date) DESC" do
|
||||
claimed_recording = FactoryGirl.create(:claimed_recording)
|
||||
|
||||
feeds, start = Feed.index(user1)
|
||||
feeds.length.should == 2
|
||||
feeds[0].recording.should == claimed_recording.recording
|
||||
feeds[1].music_session.should == claimed_recording.recording.music_session.music_session
|
||||
feeds[1].recording.should == claimed_recording.recording
|
||||
feeds[0].music_session.should == claimed_recording.recording.music_session.music_session
|
||||
end
|
||||
|
||||
it "sort by plays DESC" do
|
||||
it "sort by active flag / plays DESC" do
|
||||
claimed_recording1 = FactoryGirl.create(:claimed_recording)
|
||||
claimed_recording2 = FactoryGirl.create(:claimed_recording)
|
||||
|
||||
|
|
@ -77,8 +77,8 @@ describe Feed do
|
|||
|
||||
feeds, start = Feed.index(user1, :sort => 'plays')
|
||||
feeds.length.should == 4
|
||||
feeds[0].recording.should == claimed_recording2.recording
|
||||
feeds[1].recording.should == claimed_recording1.recording
|
||||
feeds[2].recording.should == claimed_recording2.recording
|
||||
feeds[3].recording.should == claimed_recording1.recording
|
||||
|
||||
FactoryGirl.create(:playable_play, playable: claimed_recording1.recording.music_session.music_session, user: user1)
|
||||
FactoryGirl.create(:playable_play, playable: claimed_recording1.recording.music_session.music_session, user: user2)
|
||||
|
|
@ -88,11 +88,11 @@ describe Feed do
|
|||
feeds, start = Feed.index(user1, :sort => 'plays')
|
||||
feeds.length.should == 4
|
||||
feeds[0].music_session.should == claimed_recording1.recording.music_session.music_session
|
||||
feeds[1].recording.should == claimed_recording2.recording
|
||||
feeds[2].recording.should == claimed_recording1.recording
|
||||
feeds[2].recording.should == claimed_recording2.recording
|
||||
feeds[3].recording.should == claimed_recording1.recording
|
||||
end
|
||||
|
||||
it "sort by likes DESC" do
|
||||
it "sort by active flag / likes DESC" do
|
||||
claimed_recording1 = FactoryGirl.create(:claimed_recording)
|
||||
claimed_recording2 = FactoryGirl.create(:claimed_recording)
|
||||
|
||||
|
|
@ -106,6 +106,7 @@ describe Feed do
|
|||
|
||||
feeds, start = Feed.index(user1, :sort => 'likes')
|
||||
feeds.length.should == 4
|
||||
feeds = feeds.where("feeds.music_session_id is null")
|
||||
feeds[0].recording.should == claimed_recording2.recording
|
||||
feeds[1].recording.should == claimed_recording1.recording
|
||||
|
||||
|
|
@ -116,8 +117,8 @@ describe Feed do
|
|||
feeds, start = Feed.index(user1, :sort => 'likes')
|
||||
feeds.length.should == 4
|
||||
feeds[0].music_session.should == claimed_recording1.recording.music_session.music_session
|
||||
feeds[1].recording.should == claimed_recording2.recording
|
||||
feeds[2].recording.should == claimed_recording1.recording
|
||||
feeds[2].recording.should == claimed_recording2.recording
|
||||
feeds[3].recording.should == claimed_recording1.recording
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -195,6 +196,9 @@ describe Feed do
|
|||
it "supports date pagination" do
|
||||
claimed_recording = FactoryGirl.create(:claimed_recording)
|
||||
|
||||
ams = ActiveMusicSession.find(claimed_recording.recording.music_session.music_session.id)
|
||||
ams.before_destroy
|
||||
|
||||
options = {limit: 1}
|
||||
feeds, start = Feed.index(user1, options)
|
||||
feeds.length.should == 1
|
||||
|
|
|
|||
|
|
@ -176,6 +176,16 @@ describe GetWork do
|
|||
GetWork.get_work_list(other_connection2).should == [my_connection.client_id]
|
||||
end
|
||||
|
||||
it "excludes network testing clients" do
|
||||
my_connection = FactoryGirl.create(:connection, locidispid: austin_geo[:locidispid], addr: 1)
|
||||
other_connection = FactoryGirl.create(:connection, locidispid: dallas_geo[:locidispid], addr: 2, is_network_testing: true)
|
||||
other_connection2 = FactoryGirl.create(:connection, locidispid: houston_geoip[:locidispid], addr: 3)
|
||||
|
||||
GetWork.get_work_list(my_connection).should == [other_connection2.client_id]
|
||||
GetWork.get_work_list(other_connection).should == []
|
||||
GetWork.get_work_list(other_connection2).should == [my_connection.client_id]
|
||||
end
|
||||
|
||||
it "excludes scoring_timeout clients (1)" do
|
||||
my_connection = FactoryGirl.create(:connection, locidispid: austin_geo[:locidispid], addr: 1)
|
||||
other_connection = FactoryGirl.create(:connection, locidispid: dallas_geo[:locidispid], addr: 2, scoring_timeout: 1.days.from_now)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
require 'spec_helper'
|
||||
require 'rest-client'
|
||||
|
||||
describe RecordedVideo do
|
||||
include UsesTempFiles
|
||||
let (:user) {FactoryGirl.create(:user)}
|
||||
let (:connection) {FactoryGirl.create(:connection, :user => user)}
|
||||
let (:music_session){FactoryGirl.create(:active_music_session, :creator => user, :musician_access => true)}
|
||||
let (:recording) {FactoryGirl.create(:recording, :music_session => music_session, :owner => user)}
|
||||
let (:video_source) {FactoryGirl.create(:video_source, :connection => connection)}
|
||||
|
||||
it "should create from a video source" do
|
||||
recorded_video_source = RecordedVideo.create_from_video_source(video_source, recording)
|
||||
recorded_video_source.should_not be_nil
|
||||
recorded_video_source.user.id.should == video_source.connection.user.id
|
||||
recorded_video_source.fully_uploaded.should == false
|
||||
recorded_video_source.client_video_source_id.should == video_source.id
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -7,10 +7,9 @@ describe Recording do
|
|||
@instrument = FactoryGirl.create(:instrument, :description => 'a great instrument')
|
||||
@music_session = FactoryGirl.create(:active_music_session, :creator => @user, :musician_access => true)
|
||||
@connection = FactoryGirl.create(:connection, :user => @user, :music_session => @music_session)
|
||||
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
|
||||
@track = FactoryGirl.create(:track, :connection => @connection, :instrument => @instrument)
|
||||
end
|
||||
|
||||
|
||||
|
||||
it "should allow finding of recorded tracks" do
|
||||
user2 = FactoryGirl.create(:user)
|
||||
connection2 = FactoryGirl.create(:connection, :user => user2, :music_session => @music_session)
|
||||
|
|
@ -39,7 +38,7 @@ describe Recording do
|
|||
@recorded_tracks.length.should == 1
|
||||
@recorded_tracks.first.instrument_id == @track.instrument_id
|
||||
@recorded_tracks.first.user_id == @track.connection.user_id
|
||||
end
|
||||
end
|
||||
|
||||
it "should not start a recording if the session is already being recorded" do
|
||||
Recording.start(@music_session, @user).errors.any?.should be_false
|
||||
|
|
@ -286,6 +285,64 @@ describe Recording do
|
|||
@recording2.errors.any?.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
it "set video from source" do
|
||||
@video_source = FactoryGirl.create(:video_source, :connection => @connection)
|
||||
|
||||
@music_session.is_recording?.should be_false
|
||||
@recording = Recording.start(@music_session, @user)
|
||||
@music_session.reload
|
||||
@music_session.recordings[0].should == @recording
|
||||
@recording.owner_id.should == @user.id
|
||||
|
||||
@recorded_videos = RecordedVideo.where(:recording_id => @recording.id)
|
||||
@recorded_videos.should have(1).items
|
||||
@recorded_videos[0].client_video_source_id.should eq(@video_source.id)
|
||||
end
|
||||
|
||||
it "should include video when listing uploads" do
|
||||
@video_source = FactoryGirl.create(:video_source, :connection => @connection)
|
||||
@recording = Recording.start(@music_session, @user)
|
||||
@recording.stop
|
||||
@recording.reload
|
||||
@genre = FactoryGirl.create(:genre)
|
||||
@recording.claim(@user, "Recording", "Recording Description", @genre, true)
|
||||
|
||||
# We should have 2 items; a track and a video:
|
||||
uploads = Recording.list_uploads(@user)
|
||||
uploads["uploads"].should have(2).items
|
||||
uploads["uploads"][0][:type].should eq("recorded_track")
|
||||
uploads["uploads"][1][:type].should eq("recorded_video")
|
||||
uploads["uploads"][0].should include(:client_track_id)
|
||||
uploads["uploads"][1].should include(:client_video_source_id)
|
||||
|
||||
# Next page should have nothing:
|
||||
uploads = Recording.list_uploads(@user, 10, uploads["next"])
|
||||
uploads["uploads"].should have(0).items
|
||||
end
|
||||
|
||||
it "should paginate with video" do
|
||||
@video_source = FactoryGirl.create(:video_source, :connection => @connection)
|
||||
@recording = Recording.start(@music_session, @user)
|
||||
@recording.stop
|
||||
@recording.reload
|
||||
@genre = FactoryGirl.create(:genre)
|
||||
@recording.claim(@user, "Recording", "Recording Description", @genre, true)
|
||||
|
||||
# Limit to 1, so we can test pagination:
|
||||
uploads = Recording.list_uploads(@user, 1)
|
||||
uploads["uploads"].should have(1).items # First page
|
||||
|
||||
# Second page:
|
||||
uploads = Recording.list_uploads(@user, 1, uploads["next"])
|
||||
uploads["uploads"].should have(1).items
|
||||
|
||||
# Last page (should be empty):
|
||||
uploads = Recording.list_uploads(@user, 10, uploads["next"])
|
||||
uploads["uploads"].should have(0).items
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe VideoSource do
|
||||
|
||||
let (:user) {FactoryGirl.create(:user) }
|
||||
let (:music_session) { FactoryGirl.create(:active_music_session, :creator => user)}
|
||||
let (:connection) { FactoryGirl.create(:connection, :user => user, :music_session => music_session) }
|
||||
let (:msuh) {FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => user, :client_id => connection.client_id) }
|
||||
|
||||
|
||||
before(:each) do
|
||||
msuh.touch
|
||||
end
|
||||
|
||||
describe "simple create" do
|
||||
it "create a video source" do
|
||||
video_source = FactoryGirl.create(:video_source, :connection => connection)
|
||||
video_source.should_not be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -18,7 +18,7 @@ else
|
|||
gem 'jam_websockets', "0.1.#{ENV["BUILD_NUMBER"]}"
|
||||
ENV['NOKOGIRI_USE_SYSTEM_LIBRARIES'] ||= "true"
|
||||
end
|
||||
gem 'oj'
|
||||
gem 'oj', '2.10.2'
|
||||
gem 'builder'
|
||||
gem 'rails', '~>3.2.11'
|
||||
gem 'railties', '~>3.2.11'
|
||||
|
|
@ -55,7 +55,7 @@ gem 'carrierwave_direct'
|
|||
gem 'fog'
|
||||
gem 'haml-rails'
|
||||
gem 'unf' #optional fog dependency
|
||||
gem 'devise', '>= 1.1.2'
|
||||
gem 'devise', '3.3.0' #3.4.0 causes uninitialized constant ActionController::Metal (NameError)
|
||||
gem 'postgres-copy'
|
||||
#group :libv8 do
|
||||
# gem 'libv8', "~> 3.11.8"
|
||||
|
|
|
|||
|
|
@ -101,7 +101,18 @@
|
|||
|
||||
rest.updateRsvpRequest(rsvpId, params)
|
||||
.done(refreshSessionDetail)
|
||||
.fail(app.ajaxError);
|
||||
.fail(function(jqXHR, textStatus, errorMessage) {
|
||||
if (jqXHR.status === 400) {
|
||||
app.notify(
|
||||
{
|
||||
title: "Unable to Approve RSVP",
|
||||
text: jqXHR.responseJSON.message
|
||||
});
|
||||
}
|
||||
else {
|
||||
app.ajaxError(jqXHR, textStatus, errorMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function declineRsvpRequest(e) {
|
||||
|
|
@ -132,6 +143,9 @@
|
|||
});
|
||||
|
||||
context.JK.bindHoverEvents();
|
||||
// context.JK.bindInstrumentHover($('#pendingRSVPs'));
|
||||
// context.JK.bindInstrumentHover($('#session-rsvps'));
|
||||
// context.JK.bindInstrumentHover($('#still-needed'));
|
||||
}
|
||||
|
||||
function loadSessionData() {
|
||||
|
|
@ -243,7 +257,7 @@
|
|||
$.each(pending_rsvp_request.instrument_list, function (index, instrument) {
|
||||
var instrumentId = instrument == null ? null : instrument.id;
|
||||
var inst = context.JK.getInstrumentIcon24(instrumentId);
|
||||
instrumentLogoHtml += '<img data-instrument-id="' + instrumentId + '" src="' + inst + '" width="24" height="24" /> ';
|
||||
instrumentLogoHtml += '<img title="' + instrumentId + '" hoveraction="instrument" data-instrument-id="' + instrumentId + '" src="' + inst + '" width="24" height="24" /> ';
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -281,7 +295,7 @@
|
|||
$.each(approved_rsvp.instrument_list, function(index, instrument) {
|
||||
var instrumentId = instrument == null ? null : instrument.id;
|
||||
var inst = context.JK.getInstrumentIcon24(instrumentId);
|
||||
instrumentLogoHtml += '<img src="' + inst + '" width="24" height="24" /> ';
|
||||
instrumentLogoHtml += '<img title="' + instrumentId + '" hoveraction="instrument" data-instrument-id="' + instrumentId + '" src="' + inst + '" width="24" height="24" /> ';
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -312,7 +326,7 @@
|
|||
|
||||
rsvpHtml = context._.template(
|
||||
$("#template-account-session-rsvp").html(),
|
||||
{id: approved_rsvp.id, user_id: approved_rsvp.user_id, avatar_url: avatar_url,
|
||||
{id: approved_rsvp.id, avatar_url: avatar_url,
|
||||
user_name: approved_rsvp.name, instruments: instrumentLogoHtml,
|
||||
latency: latencyHtml, is_owner: sessionData.isOwner, request_id: request_id},
|
||||
{variable: 'data'}
|
||||
|
|
@ -346,7 +360,7 @@
|
|||
|
||||
resultHtml += context._.template(
|
||||
$("#template-account-invited").html(),
|
||||
{avatar_url: avatar_url, user_id: invitation.reciever_id},
|
||||
{avatar_url: avatar_url, user_id: invitation.receiver_id},
|
||||
{variable: 'data'}
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -54,13 +54,14 @@
|
|||
}
|
||||
|
||||
function beforeShow() {
|
||||
networkTest.haltScoring();
|
||||
if(!networkTest.isScoring()) {
|
||||
networkTest.reset();
|
||||
}
|
||||
}
|
||||
|
||||
function afterHide() {
|
||||
|
||||
networkTest.resumeScoring();
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
|
|
|||
|
|
@ -140,6 +140,9 @@
|
|||
}
|
||||
|
||||
function updateScoringIntervals() {
|
||||
// make sure latency testing is still going on, in case a refresh occurred during network test
|
||||
context.jamClient.SetLatencyTestBlocked(false)
|
||||
|
||||
// set scoring intervals
|
||||
if(context.jamClient.SetScoreWorkTimingInterval){
|
||||
var success = context.jamClient.SetScoreWorkTimingInterval(
|
||||
|
|
|
|||
|
|
@ -362,6 +362,18 @@
|
|||
return 8;
|
||||
}
|
||||
|
||||
function SetLatencyTestBlocked(blocked) {
|
||||
|
||||
}
|
||||
|
||||
function isLatencyTestBlocked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function GetLastLatencyTestTimes() {
|
||||
return { initiated: 10000, requested: 10000}
|
||||
}
|
||||
|
||||
function GetASIODevices() {
|
||||
var response =[{"device_id":0,"device_name":"Realtek High Definition Audio","device_type": 0,"interfaces":[{"interface_id":0,"interface_name":"Realtek HDA SPDIF Out","pins":[{"is_input":false,"pin_id":0,"pin_name":"PC Speaker"}]},{"interface_id":1,"interface_name":"Realtek HD Audio rear output","pins":[{"is_input":false,"pin_id":0,"pin_name":"PC Speaker"}]},{"interface_id":2,"interface_name":"Realtek HD Audio Mic input","pins":[{"is_input":true,"pin_id":0,"pin_name":"Recording Control"}]},{"interface_id":3,"interface_name":"Realtek HD Audio Line input","pins":[{"is_input":true,"pin_id":0,"pin_name":"Recording Control"}]},{"interface_id":4,"interface_name":"Realtek HD Digital input","pins":[{"is_input":true,"pin_id":0,"pin_name":"Capture"}]},{"interface_id":5,"interface_name":"Realtek HD Audio Stereo input","pins":[{"is_input":true,"pin_id":0,"pin_name":"Recording Control"}]}],"wavert_supported":false},{"device_id":1,"device_name":"M-Audio FW Audiophile","device_type": 1,"interfaces":[{"interface_id":0,"interface_name":"FW AP Multi","pins":[{"is_input":false,"pin_id":0,"pin_name":"Output"},{"is_input":true,"pin_id":1,"pin_name":"Input"}]},{"interface_id":1,"interface_name":"FW AP 1/2","pins":[{"is_input":false,"pin_id":0,"pin_name":"Output"},{"is_input":true,"pin_id":1,"pin_name":"Input"}]},{"interface_id":2,"interface_name":"FW AP SPDIF","pins":[{"is_input":false,"pin_id":0,"pin_name":"Output"},{"is_input":true,"pin_id":1,"pin_name":"Input"}]},{"interface_id":3,"interface_name":"FW AP 3/4","pins":[{"is_input":false,"pin_id":0,"pin_name":"Output"}]}],"wavert_supported":false},{"device_id":2,"device_name":"Virtual Audio Cable","device_type": 2,"interfaces":[{"interface_id":0,"interface_name":"Virtual Cable 2","pins":[{"is_input":true,"pin_id":0,"pin_name":"Capture"},{"is_input":false,"pin_id":1,"pin_name":"Output"}]},{"interface_id":1,"interface_name":"Virtual Cable 1","pins":[{"is_input":true,"pin_id":0,"pin_name":"Capture"},{"is_input":false,"pin_id":1,"pin_name":"Output"}]}],"wavert_supported":false},{"device_id":3,"device_name":"WebCamDV WDM Audio Capture","device_type": 3,"interfaces":[{"interface_id":0,"interface_name":"WebCamDV Audio","pins":[{"is_input":true,"pin_id":0,"pin_name":"Recording Control"},{"is_input":false,"pin_id":1,"pin_name":"Volume Control"}]}],"wavert_supported":false}];
|
||||
return response;
|
||||
|
|
@ -823,6 +835,9 @@
|
|||
this.IsMyNetworkWireless = IsMyNetworkWireless;
|
||||
this.SetNetworkTestScore = SetNetworkTestScore;
|
||||
this.GetNetworkTestScore = GetNetworkTestScore;
|
||||
this.SetLatencyTestBlocked = SetLatencyTestBlocked;
|
||||
this.isLatencyTestBlocked = isLatencyTestBlocked;
|
||||
this.GetLastLatencyTestTimes = GetLastLatencyTestTimes;
|
||||
this.RegisterQuitCallback = RegisterQuitCallback;
|
||||
this.LeaveSessionAndMinimize = LeaveSessionAndMinimize;
|
||||
this.GetAutoStart = GetAutoStart;
|
||||
|
|
|
|||
|
|
@ -85,6 +85,9 @@
|
|||
context.JK.bindHoverEvents();
|
||||
$ssSpinner.hide();
|
||||
});
|
||||
|
||||
// context.JK.bindInstrumentHover($(CATEGORY.ACTIVE.id));
|
||||
// context.JK.bindInstrumentHover($(CATEGORY.SCHEDULED.id));
|
||||
}
|
||||
|
||||
/***************** ACTIVE SESSIONS *****************/
|
||||
|
|
|
|||
|
|
@ -503,6 +503,19 @@
|
|||
});
|
||||
}
|
||||
|
||||
function updateNetworkTesting(options) {
|
||||
var id = getId(options);
|
||||
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: 'application/json',
|
||||
url: "/api/users/" + id + "/is_network_testing",
|
||||
data: JSON.stringify(options),
|
||||
processData: false
|
||||
});
|
||||
}
|
||||
|
||||
function updateAvatar(options) {
|
||||
var id = getId(options);
|
||||
|
||||
|
|
@ -1222,6 +1235,7 @@
|
|||
this.getInstruments = getInstruments;
|
||||
this.getGenres = getGenres;
|
||||
this.updateUdpReachable = updateUdpReachable;
|
||||
this.updateNetworkTesting = updateNetworkTesting;
|
||||
this.updateAvatar = updateAvatar;
|
||||
this.deleteAvatar = deleteAvatar;
|
||||
this.getFilepickerPolicy = getFilepickerPolicy;
|
||||
|
|
|
|||
|
|
@ -123,11 +123,11 @@
|
|||
*/
|
||||
function ajaxError(jqXHR, textStatus, errorMessage) {
|
||||
|
||||
if (jqXHR.status == 404) {
|
||||
if (jqXHR.status === 404) {
|
||||
logger.error("Unexpected ajax error: " + textStatus + ", msg:" + errorMessage);
|
||||
app.notify({title: "Oops!", text: "What you were looking for is gone now."});
|
||||
}
|
||||
else if (jqXHR.status = 422) {
|
||||
else if (jqXHR.status === 422) {
|
||||
logger.error("Unexpected ajax error: " + textStatus + ", msg: " + errorMessage + ", response: " + jqXHR.responseText);
|
||||
// present a nicer message
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -167,6 +167,35 @@
|
|||
return lastNetworkFailure;
|
||||
}
|
||||
|
||||
function haltScoring() {
|
||||
context.jamClient.SetLatencyTestBlocked(true)
|
||||
rest.updateNetworkTesting({client_id: app.clientId, is_network_testing: true})
|
||||
.fail(function(jqXHR) {
|
||||
|
||||
if(jqXHR.status == 404) {
|
||||
// assume connection is missing
|
||||
app.notifyAlert("Not Connected", "You must be connected to the server to run the network test.")
|
||||
}
|
||||
else {
|
||||
app.notifyServerError(jqXHR, "Unable to tell server that we are beginning the network test")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function resumeScoring() {
|
||||
context.jamClient.SetLatencyTestBlocked(false)
|
||||
rest.updateNetworkTesting({client_id: app.clientId, is_network_testing: false})
|
||||
.fail(function(jqXHR) {
|
||||
if(jqXHR.status == 404) {
|
||||
// assume connection is missing
|
||||
// do nothing in this case
|
||||
}
|
||||
else {
|
||||
app.notifyServerError(jqXHR, "Unable to tell server that we are ending the network test")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function storeLastNetworkFailure(reason, data) {
|
||||
if (!trackedPass) {
|
||||
lastNetworkFailure = {reason: reason, data: data};
|
||||
|
|
@ -471,63 +500,125 @@
|
|||
}
|
||||
}
|
||||
|
||||
function pauseForRecentScoresTime() {
|
||||
var lastScoreTimes = context.jamClient.GetLastLatencyTestTimes()
|
||||
|
||||
console.log(lastScoreTimes)
|
||||
|
||||
return 0;
|
||||
|
||||
var noPause = 0;
|
||||
var longAgo = 1000000;
|
||||
var initiated = lastScoreTimes.initiatied;
|
||||
var requested = lastScoreTimes.requested;
|
||||
|
||||
if(initiated === null || initiated === undefined) {
|
||||
logger.warn("lastScoreTimes.initiated is not set");
|
||||
initiated = longAgo;
|
||||
}
|
||||
if(requested === null || requested === undefined) {
|
||||
logger.warn("lastScoreTimes.requested is not set");
|
||||
requested = longAgo;
|
||||
}
|
||||
|
||||
if(initiated == 0) {
|
||||
logger.debug("lastScoreTimes.initiated is zero");
|
||||
initiated = longAgo;
|
||||
}
|
||||
if(requested == 0) {
|
||||
logger.debug("lastScoreTimes.requested is zero");
|
||||
requested = longAgo;
|
||||
}
|
||||
|
||||
if(initiated < 0) {
|
||||
logger.debug("lastScoreTimes.initiated is less than zero");
|
||||
initiated = longAgo;
|
||||
}
|
||||
if(requested < 0) {
|
||||
logger.debug("lastScoreTimes.requested is less than zero");
|
||||
requested = longAgo;
|
||||
}
|
||||
|
||||
var mostRecentValue = initiated < requested ? initiated : requested;
|
||||
|
||||
if(mostRecentValue > gon.globalftue_network_test_min_wait_since_last_score * 1000) {
|
||||
return noPause; // our last score was past our min wait; so no delay necessary
|
||||
}
|
||||
else {
|
||||
// pause for the remainder of the min wait threshold
|
||||
var remainder = gon.globalftue_network_test_min_wait_since_last_score * 1000 - mostRecentValue;
|
||||
|
||||
if(remainder > 1500) {
|
||||
// we need to update the UI because this is a long time for a mystery pause
|
||||
$startNetworkTestBtn.text('SHORT QUIET PERIOD...')
|
||||
}
|
||||
|
||||
return remainder;
|
||||
}
|
||||
}
|
||||
function prepareNetworkTest() {
|
||||
|
||||
if (scoring) return false;
|
||||
logger.info("starting network test");
|
||||
resetTestState();
|
||||
scoring = true;
|
||||
$self.triggerHandler(NETWORK_TEST_START);
|
||||
renderStartTest();
|
||||
rest.getLatencyTester()
|
||||
.done(function (response) {
|
||||
// ensure there are no tests ongoing
|
||||
|
||||
serverClientId = response.client_id;
|
||||
|
||||
testSummary.serverClientId = serverClientId;
|
||||
setTimeout(function() {
|
||||
|
||||
logger.info("beginning network test against client_id: " + serverClientId);
|
||||
logger.info("starting network test");
|
||||
resetTestState();
|
||||
scoring = true;
|
||||
$self.triggerHandler(NETWORK_TEST_START);
|
||||
renderStartTest();
|
||||
rest.getLatencyTester()
|
||||
.done(function (response) {
|
||||
// ensure there are no tests ongoing
|
||||
|
||||
primePump()
|
||||
.done(function () {
|
||||
postPumpRun();
|
||||
})
|
||||
.fail(function () {
|
||||
logger.debug("unable to determine user's network type. primePump failed.")
|
||||
context.JK.Banner.showAlert({
|
||||
title: 'Unable to Determine Network Type',
|
||||
buttons: [
|
||||
{name: 'CANCEL', click: function () {
|
||||
cancelTest();
|
||||
}},
|
||||
{name: 'RUN NETWORK TEST ANYWAY', click: function () {
|
||||
attemptTestPass();
|
||||
;
|
||||
}}
|
||||
],
|
||||
html: "<p>We are unable to determine if your computer is connected to your network using WiFi.</p>" +
|
||||
"<p>We strongly advise against running the JamKazam application on a WiFi connection. " +
|
||||
"We recommend using a wired Ethernet connection from your computer to your router. " +
|
||||
"A WiFi connection is likely to cause significant issues in both latency and audio quality.</p>"})
|
||||
});
|
||||
})
|
||||
.fail(function (jqXHR) {
|
||||
if (jqXHR.status == 404) {
|
||||
// means there are no network testers available.
|
||||
// we have to skip this part of the UI
|
||||
testSummary.final = {reason: 'no_servers'}
|
||||
}
|
||||
else {
|
||||
if (context.JK.isNetworkError(arguments)) {
|
||||
testSummary.final = {reason: 'no_network'}
|
||||
serverClientId = response.client_id;
|
||||
|
||||
testSummary.serverClientId = serverClientId;
|
||||
|
||||
logger.info("beginning network test against client_id: " + serverClientId);
|
||||
|
||||
primePump()
|
||||
.done(function () {
|
||||
postPumpRun();
|
||||
})
|
||||
.fail(function () {
|
||||
logger.debug("unable to determine user's network type. primePump failed.")
|
||||
context.JK.Banner.showAlert({
|
||||
title: 'Unable to Determine Network Type',
|
||||
buttons: [
|
||||
{name: 'CANCEL', click: function () {
|
||||
cancelTest();
|
||||
}},
|
||||
{name: 'RUN NETWORK TEST ANYWAY', click: function () {
|
||||
attemptTestPass();
|
||||
;
|
||||
}}
|
||||
],
|
||||
html: "<p>We are unable to determine if your computer is connected to your network using WiFi.</p>" +
|
||||
"<p>We strongly advise against running the JamKazam application on a WiFi connection. " +
|
||||
"We recommend using a wired Ethernet connection from your computer to your router. " +
|
||||
"A WiFi connection is likely to cause significant issues in both latency and audio quality.</p>"})
|
||||
});
|
||||
})
|
||||
.fail(function (jqXHR) {
|
||||
if (jqXHR.status == 404) {
|
||||
// means there are no network testers available.
|
||||
// we have to skip this part of the UI
|
||||
testSummary.final = {reason: 'no_servers'}
|
||||
}
|
||||
else {
|
||||
testSummary.final = {reason: 'rest_api_error'}
|
||||
if (context.JK.isNetworkError(arguments)) {
|
||||
testSummary.final = {reason: 'no_network'}
|
||||
}
|
||||
else {
|
||||
testSummary.final = {reason: 'rest_api_error'}
|
||||
}
|
||||
}
|
||||
}
|
||||
testFinished();
|
||||
})
|
||||
testFinished();
|
||||
})
|
||||
}, pauseForRecentScoresTime())
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -844,6 +935,8 @@
|
|||
this.reset = reset;
|
||||
this.cancel = cancel;
|
||||
this.getLastNetworkFailure = getLastNetworkFailure;
|
||||
this.haltScoring = haltScoring;
|
||||
this.resumeScoring = resumeScoring;
|
||||
|
||||
this.NETWORK_TEST_START = NETWORK_TEST_START;
|
||||
this.NETWORK_TEST_DONE = NETWORK_TEST_DONE;
|
||||
|
|
|
|||
|
|
@ -369,7 +369,7 @@
|
|||
var track = participant.tracks[j];
|
||||
logger.debug("Find:Finding instruments. Participant tracks:", participant.tracks);
|
||||
var inst = context.JK.getInstrumentIcon24(track.instrument_id);
|
||||
instrumentLogoHtml += '<img src="' + inst + '" width="24" height="24" /> ';
|
||||
instrumentLogoHtml += '<img title="' + track.instrument_id + '" hoveraction="instrument" data-instrument-id="' + track.instrument_id + '" src="' + inst + '" width="24" height="24" /> ';
|
||||
}
|
||||
|
||||
var id = participant.user.id;
|
||||
|
|
@ -400,7 +400,7 @@
|
|||
for (j=0; j < user.instrument_list.length; j++) {
|
||||
var instrument = user.instrument_list[j];
|
||||
var inst = context.JK.getInstrumentIcon24(instrument.id);
|
||||
instrumentLogoHtml += '<img src="' + inst + '" width="24" height="24" /> ';
|
||||
instrumentLogoHtml += '<img title="' + instrument.id + '" hoveraction="instrument" data-instrument-id="' + instrument.id + '" src="' + inst + '" width="24" height="24" /> ';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -239,6 +239,9 @@
|
|||
var instrumentId = $element.attr('data-instrument-id');
|
||||
|
||||
if(instrumentId) {
|
||||
if (instrumentId === "null") {
|
||||
instrumentId = "not specified";
|
||||
}
|
||||
context.JK.hoverBubble($element, instrumentId, options);
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -53,11 +53,13 @@
|
|||
}
|
||||
|
||||
function beforeShow() {
|
||||
networkTest.haltScoring();
|
||||
networkTest.cancel();
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
function beforeHide() {
|
||||
networkTest.resumeScoring();
|
||||
networkTest.cancel();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -672,8 +672,17 @@ class ApiUsersController < ApiController
|
|||
def udp_reachable
|
||||
Connection.transaction do
|
||||
@connection = Connection.find_by_client_id!(params[:client_id])
|
||||
@connection.udp_reachable = params[:udp_reachable]
|
||||
@connection.save
|
||||
# deliberately don't updated_at on connection! only heartbeats do that
|
||||
Connection.where(:id => @connection.id).update_all(:udp_reachable => params[:udp_reachable])
|
||||
respond_with_model(@connection)
|
||||
end
|
||||
end
|
||||
|
||||
def is_network_testing
|
||||
Connection.transaction do
|
||||
@connection = Connection.find_by_client_id!(params[:client_id])
|
||||
# deliberately don't updated_at on connection! only heartbeats do that
|
||||
Connection.where(:id => @connection.id).update_all(:is_network_testing => params[:is_network_testing])
|
||||
respond_with_model(@connection)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -248,6 +248,8 @@ if defined?(Bundler)
|
|||
config.ftue_network_test_packet_size = 60
|
||||
# number of times that the backend retries before giving up
|
||||
config.ftue_network_test_backend_retries = 10
|
||||
# amount of time that we want passed until we run the next network test
|
||||
config.ftue_network_test_min_wait_since_last_score = 5
|
||||
# the maximum amount of allowable latency
|
||||
config.ftue_maximum_gear_latency = 20
|
||||
|
||||
|
|
|
|||
|
|
@ -4,4 +4,5 @@ Gon.global.ftue_network_test_backend_retries = Rails.application.config.ftue_net
|
|||
Gon.global.twitter_public_account = Rails.application.config.twitter_public_account
|
||||
Gon.global.scoring_get_work_interval = Rails.application.config.scoring_get_work_interval
|
||||
Gon.global.scoring_get_work_backoff_interval = Rails.application.config.scoring_get_work_backoff_interval
|
||||
Gon.global.ftue_network_test_min_wait_since_last_score = Rails.application.config.ftue_network_test_min_wait_since_last_score
|
||||
Gon.global.env = Rails.env
|
||||
|
|
|
|||
|
|
@ -297,6 +297,7 @@ SampleApp::Application.routes.draw do
|
|||
|
||||
# udp reachable (can stun?)
|
||||
match '/users/:id/udp_reachable' => 'api_users#udp_reachable', :via => :post
|
||||
match '/users/:id/is_network_testing' => 'api_users#is_network_testing', :via => :post
|
||||
|
||||
# social
|
||||
match '/users/:id/share/session/:provider' => 'api_users#share_session', :via => :get
|
||||
|
|
|
|||
|
|
@ -94,6 +94,9 @@ describe ApiFeedsController do
|
|||
claimed_recording.recording.created_at = 3.days.ago
|
||||
claimed_recording.recording.save!
|
||||
|
||||
ams = ActiveMusicSession.find(claimed_recording.recording.music_session.music_session.id)
|
||||
ams.before_destroy
|
||||
|
||||
get :index, { limit: 1 }
|
||||
json = JSON.parse(response.body, :symbolize_names => true)
|
||||
json[:entries].length.should == 1
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ gem 'rb-readline'
|
|||
gem 'aasm', '3.0.16'
|
||||
gem 'carrierwave'
|
||||
gem 'fog'
|
||||
gem 'devise'
|
||||
gem 'devise', '3.3.0' # 3.4.0 causes uninitialized constant ActionController::Metal (NameError)
|
||||
gem 'postgres-copy'
|
||||
gem 'aws-sdk' #, '1.29.1'
|
||||
gem 'bugsnag'
|
||||
|
|
|
|||
Loading…
Reference in New Issue