merging with develop

This commit is contained in:
Jonathan Kolyer 2014-05-21 21:55:26 +00:00
commit 836baee962
39 changed files with 430 additions and 334 deletions

View File

@ -154,4 +154,5 @@ fix_connection_fields.sql
session_ratings.sql
scheduled_sessions.sql
add_last_jam_user_fields.sql
periodic_emails.sql
remove_lat_lng_user_fields.sql
update_get_work_for_larger_radius.sql

View File

@ -0,0 +1,2 @@
alter table users drop column lat;
alter table users drop column lng;

View File

@ -0,0 +1,16 @@
DROP FUNCTION get_work (mylocidispid BIGINT);
CREATE FUNCTION get_work (mylocidispid BIGINT, myaddr BIGINT) RETURNS TABLE (client_id VARCHAR(64)) ROWS 5 VOLATILE AS $$
BEGIN
CREATE TEMPORARY TABLE foo (locidispid BIGINT, locid INT);
INSERT INTO foo SELECT DISTINCT locidispid, locidispid/1000000 FROM connections WHERE client_type = 'client';
DELETE FROM foo WHERE locidispid IN (SELECT DISTINCT blocidispid FROM current_scores WHERE alocidispid = mylocidispid AND (current_timestamp - score_dt) < INTERVAL '24 hours');
DELETE FROM foo WHERE locid NOT IN (SELECT locid FROM geoiplocations WHERE geog && st_buffer((SELECT geog FROM geoiplocations WHERE locid = mylocidispid/1000000), 4023360));
CREATE TEMPORARY TABLE bar (client_id VARCHAR(64), locidispid BIGINT, r DOUBLE PRECISION);
INSERT INTO bar SELECT l.client_id, l.locidispid, random() FROM connections l, foo f WHERE l.locidispid = f.locidispid AND l.client_type = 'client' AND addr != myaddr;
DROP TABLE foo;
DELETE FROM bar b WHERE r != (SELECT MAX(r) FROM bar b0 WHERE b0.locidispid = b.locidispid);
RETURN QUERY SELECT b.client_id FROM bar b ORDER BY r LIMIT 5;
DROP TABLE bar;
RETURN;
END;
$$ LANGUAGE plpgsql;

View File

@ -4,4 +4,4 @@ dropdb jam_db_build
dropdb jam_ruby_test
dropdb jam_web_test
dropdb jam_websocket_test
createdb -Upostgres jam
sudo su postgres -c "createdb jam"

View File

@ -134,7 +134,7 @@ module JamRuby
end
def did_create
self.user.update_lat_lng(self.ip_address) if self.user && self.ip_address
# self.user.update_lat_lng(self.ip_address) if self.user && self.ip_address
end
def report_add_participant

View File

@ -3,15 +3,15 @@ module JamRuby
self.table_name = "connections"
def self.get_work(mylocidispid)
list = self.get_work_list(mylocidispid)
def self.get_work(mylocidispid, myaddr)
list = self.get_work_list(mylocidispid, myaddr)
return nil if list.nil?
return nil if list.length == 0
return list[0]
end
def self.get_work_list(mylocidispid)
r = GetWork.select(:client_id).find_by_sql("select get_work(#{mylocidispid}) as client_id")
def self.get_work_list(mylocidispid, myaddr)
r = GetWork.select(:client_id).find_by_sql("select get_work(#{mylocidispid}, #{myaddr}) as client_id")
#puts("r = #{r}")
a = r.map {|i| i.client_id}
#puts("a = #{a}")

View File

@ -88,35 +88,42 @@ module JamRuby
end
end
end
User.find_each { |usr| usr.update_lat_lng }
# User.find_each { |usr| usr.update_lat_lng }
Band.find_each { |bnd| bnd.update_lat_lng }
end
def self.where_latlng(relation, params, current_user=nil)
if 0 < (distance = params[:distance].to_i)
latlng = []
if location_city = params[:city]
if geo = self.where(:city => params[:city]).limit(1).first
# this is only valid to call when relation is about bands
distance = params[:distance].to_i
if distance > 0
latlng = nil
location_city = params[:city]
location_state = params[:state]
location_country = params[:country]
remote_ip = params[:remote_ip]
if location_city and location_state and location_country
geo = self.where(city: location_city, region: location_state, country: location_country).limit(1).first
if geo and geo.lat and geo.lng and (geo.lat != 0 or geo.lng != 0)
# it isn't reasonable for both to be 0...
latlng = [geo.lat, geo.lng]
end
elsif current_user
if current_user.lat.nil? || current_user.lng.nil?
if params[:remote_ip] && (geo = self.ip_lookup(params[:remote_ip]))
geo.lat = nil if geo.lat = 0
geo.lng = nil if geo.lng = 0
latlng = [geo.lat, geo.lng] if geo.lat && geo.lng
end
else
latlng = [current_user.lat, current_user.lng]
elsif current_user and current_user.locidispid and current_user.locidispid != 0
location = GeoIpLocations.lookup(current_user.locidispid/1000000)
if location and location.latitude and location.longitude and (location.latitude != 0 or location.longitude != 0)
# it isn't reasonable for both to be 0...
latlng = [location.latitude, location.longitude]
end
elsif remote_ip
geo = self.ip_lookup(remote_ip)
if geo and geo.lat and geo.lng and (geo.lat != 0 or geo.lng != 0)
# it isn't reasonable for both to be 0...
latlng = [geo.lat, geo.lng]
end
elsif params[:remote_ip] && (geo = self.ip_lookup(params[:remote_ip]))
geo.lat = nil if geo.lat = 0
geo.lng = nil if geo.lng = 0
latlng = [geo.lat, geo.lng] if geo.lat && geo.lng
end
if latlng.present?
relation = relation.where(['lat IS NOT NULL AND lng IS NOT NULL'])
.within(distance, :origin => latlng)
if latlng
relation = relation.where(['lat IS NOT NULL AND lng IS NOT NULL']).within(distance, origin: latlng)
end
end
relation

View File

@ -9,8 +9,10 @@ module JamRuby
default_scope order('score_dt desc')
def self.createx(alocidispid, anodeid, aaddr, blocidispid, bnodeid, baddr, score, score_dt)
def self.createx(alocidispid, anodeid, aaddr, blocidispid, bnodeid, baddr, score, score_dt=nil)
score_dt = Time.new.utc if score_dt.nil?
score = score.ceil
raise "score must be positive" if score <= 0
Score.create(alocidispid: alocidispid, anodeid: anodeid, aaddr: aaddr, blocidispid: blocidispid, bnodeid: bnodeid, baddr: baddr, score: score, scorer: 0, score_dt: score_dt)
Score.create(alocidispid: blocidispid, anodeid: bnodeid, aaddr: baddr, blocidispid: alocidispid, bnodeid: anodeid, baddr: aaddr, score: score, scorer: 1, score_dt: score_dt) if alocidispid != blocidispid
end
@ -25,5 +27,9 @@ module JamRuby
return -1 if s.nil?
return s.score
end
def self.score_conns(c1, c2, score)
self.createx(c1.locidispid, c1.client_id, c1.addr, c2.locidispid, c2.client_id, c2.addr, score)
end
end
end

View File

@ -120,14 +120,32 @@ module JamRuby
ordering.blank? ? keys[0] : keys.detect { |oo| oo.to_s == ordering }
end
def self.musician_filter(params={}, current_user=nil)
# produce a list of musicians (users where musician is true)
# params:
# instrument - instrument to search for or blank
# handled by relation_pagination:
# page - page number to fetch (origin 1)
# per_page - number of entries per page
# handled by order_param:
# orderby - ??? (followed, plays, playing)
# handled by where_latlng:
# distance - defunct
# city - defunct
# remote_ip - defunct
def self.musician_filter(params={}, user=nil, conn=nil)
rel = User.musicians
unless (instrument = params[:instrument]).blank?
rel = rel.joins("RIGHT JOIN musicians_instruments AS minst ON minst.user_id = users.id")
.where(['minst.instrument_id = ? AND users.id IS NOT NULL', instrument])
end
rel = MaxMindGeo.where_latlng(rel, params, current_user)
locidispid = (conn ? conn.locidispid : (user ? user.last_jam_locidispid : 0))
# to find appropriate musicians we need to join users with connections to get to their locidispid,
# then join scores with alocidispid found above with the musicians' locidispid to weed out users
# with no scores or bad scores
# todo scott - rel = MaxMindGeo.where_latlng(rel, params, user)
sel_str = 'users.*'
case ordering = self.order_param(params)
@ -157,7 +175,7 @@ module JamRuby
srch = Search.new
srch.search_type = :musicians_filter
srch.page_num, srch.page_count = page, objs.total_pages
srch.musician_results_for_user(objs, current_user)
srch.musician_results_for_user(objs, user)
end
def self.relation_pagination(rel, params)
@ -274,9 +292,9 @@ module JamRuby
end
def self.new_musicians(usr, since_date=Time.now - 1.week, max_count=50, radius=M_MILES_DEFAULT)
# todo scott turn this into score .within(radius, :origin => [usr.lat, usr.lng])
rel = User.musicians
.where(['created_at >= ? AND users.id != ?', since_date, usr.id])
.within(radius, :origin => [usr.lat, usr.lng])
.order('created_at DESC')
.limit(max_count)
objs = rel.all.to_a

View File

@ -12,9 +12,9 @@ module JamRuby
include Geokit::ActsAsMappable::Glue unless defined?(acts_as_mappable)
acts_as_mappable
after_save :check_lat_lng
# after_save :check_lat_lng
attr_accessible :first_name, :last_name, :email, :city, :password, :password_confirmation, :state, :country, :birth_date, :subscribe_email, :terms_of_service, :original_fpfile, :cropped_fpfile, :cropped_large_fpfile, :cropped_s3_path, :cropped_large_s3_path, :photo_url, :large_photo_url, :crop_selection, :lat, :lng
attr_accessible :first_name, :last_name, :email, :city, :password, :password_confirmation, :state, :country, :birth_date, :subscribe_email, :terms_of_service, :original_fpfile, :cropped_fpfile, :cropped_large_fpfile, :cropped_s3_path, :cropped_large_s3_path, :photo_url, :large_photo_url, :crop_selection
# updating_password corresponds to a lost_password
attr_accessor :updating_password, :updating_email, :updated_email, :update_email_confirmation_url, :administratively_created, :current_password, :setting_password, :confirm_current_password, :updating_avatar, :updating_progression_field, :mods_json
@ -140,8 +140,8 @@ module JamRuby
scope :musicians, where(:musician => true)
scope :fans, where(:musician => false)
scope :geocoded_users, where(['lat IS NOT NULL AND lng IS NOT NULL'])
scope :musicians_geocoded, musicians.geocoded_users
# todo scott someone with locidispid - scope :geocoded_users, where(['lat IS NOT NULL AND lng IS NOT NULL'])
# todo scott geocoded_users that are musicians - scope :musicians_geocoded, musicians.geocoded_users
scope :email_opt_in, where(:subscribe_email => true)
def user_progression_fields
@ -1103,55 +1103,56 @@ module JamRuby
!self.city.blank? && (!self.state.blank? || !self.country.blank?)
end
def check_lat_lng
if (city_changed? || state_changed? || country_changed?) && !lat_changed? && !lng_changed?
update_lat_lng
end
end
# def check_lat_lng
# if (city_changed? || state_changed? || country_changed?) && !lat_changed? && !lng_changed?
# update_lat_lng
# end
# end
def update_lat_lng(ip_addy=nil)
if provides_location? # ip_addy argument ignored in this case
return false unless ip_addy.nil? # do nothing if attempting to set latlng from an ip address
query = { :city => self.city }
query[:region] = self.state unless self.state.blank?
query[:country] = self.country unless self.country.blank?
if geo = MaxMindGeo.where(query).limit(1).first
geo.lat = nil if geo.lat = 0
geo.lng = nil if geo.lng = 0
if geo.lat && geo.lng && (self.lat != geo.lat || self.lng != geo.lng)
self.update_attributes({ :lat => geo.lat, :lng => geo.lng })
return true
end
end
elsif ip_addy
if geo = MaxMindGeo.ip_lookup(ip_addy)
geo.lat = nil if geo.lat = 0
geo.lng = nil if geo.lng = 0
if self.lat != geo.lat || self.lng != geo.lng
self.update_attributes({ :lat => geo.lat, :lng => geo.lng })
return true
end
end
else
if self.lat || self.lng
self.update_attributes({ :lat => nil, :lng => nil })
return true
end
end
false
end
# def update_lat_lng(ip_addy=nil)
# if provides_location? # ip_addy argument ignored in this case
# return false unless ip_addy.nil? # do nothing if attempting to set latlng from an ip address
# query = { :city => self.city }
# query[:region] = self.state unless self.state.blank?
# query[:country] = self.country unless self.country.blank?
# if geo = MaxMindGeo.where(query).limit(1).first
# geo.lat = nil if geo.lat = 0
# geo.lng = nil if geo.lng = 0
# if geo.lat && geo.lng && (self.lat != geo.lat || self.lng != geo.lng)
# self.update_attributes({ :lat => geo.lat, :lng => geo.lng })
# return true
# end
# end
# elsif ip_addy
# if geo = MaxMindGeo.ip_lookup(ip_addy)
# geo.lat = nil if geo.lat = 0
# geo.lng = nil if geo.lng = 0
# if self.lat != geo.lat || self.lng != geo.lng
# self.update_attributes({ :lat => geo.lat, :lng => geo.lng })
# return true
# end
# end
# else
# if self.lat || self.lng
# self.update_attributes({ :lat => nil, :lng => nil })
# return true
# end
# end
# false
# end
def current_city(ip_addy=nil)
unless self.city
if self.lat && self.lng
# todo this is really dumb, you can't compare lat lng for equality
return MaxMindGeo.where(['lat = ? AND lng = ?',self.lat,self.lng]).limit(1).first.try(:city)
elsif ip_addy
return MaxMindGeo.ip_lookup(ip_addy).try(:city)
end
else
return self.city
end
# unless self.city
# if self.lat && self.lng
# # todo this is really dumb, you can't compare lat lng for equality
# return MaxMindGeo.where(['lat = ? AND lng = ?',self.lat,self.lng]).limit(1).first.try(:city)
# elsif ip_addy
# return MaxMindGeo.ip_lookup(ip_addy).try(:city)
# end
# else
# return self.city
# end
self.city
end
def update_addr_loc(connection, reason)
@ -1176,11 +1177,12 @@ module JamRuby
def self.deliver_new_musician_notifications(since_date=nil)
since_date ||= Time.now-1.week
self.geocoded_users.find_each do |usr|
Search.new_musicians(usr, since_date) do |new_nearby|
UserMailer.new_musicians(usr, new_nearby).deliver
end
end
# todo scott return musicians with locidispid not null
# self.geocoded_users.find_each do |usr|
# Search.new_musicians(usr, since_date) do |new_nearby|
# UserMailer.new_musicians(usr, new_nearby).deliver
# end
# end
end
def facebook_invite!

View File

@ -7,13 +7,13 @@ describe GetWork do
end
it "get_work_1" do
x = GetWork.get_work(1)
x = GetWork.get_work(1, 0)
#puts x.inspect
x.should be_nil
end
it "get_work_list_1" do
x = GetWork.get_work_list(1)
x = GetWork.get_work_list(1, 0)
#puts x.inspect
x.should eql([])
end

View File

@ -3,8 +3,8 @@ require 'spec_helper'
describe 'Musician search' do
before(:each) do
@geocode1 = FactoryGirl.create(:geocoder)
@geocode2 = FactoryGirl.create(:geocoder)
# @geocode1 = FactoryGirl.create(:geocoder)
# @geocode2 = FactoryGirl.create(:geocoder)
@users = []
@users << @user1 = FactoryGirl.create(:user)
@users << @user2 = FactoryGirl.create(:user)
@ -276,6 +276,7 @@ describe 'Musician search' do
context 'new users' do
it "find nearby" do
pending 'todo scott fix this test so it does something'
# create new user outside 500 from Apex to ensure its excluded from results
FactoryGirl.create(:user, {city: "Austin", state: "TX", country: "US"})
User.geocoded_users.find_each do |usr|
@ -288,6 +289,7 @@ describe 'Musician search' do
end
it "sends new musician email" do
pending 'todo scott fix this test so it does something'
# create new user outside 500 from Apex to ensure its excluded from results
FactoryGirl.create(:user, {city: "Austin", state: "TX", country: "US"})
User.geocoded_users.find_each do |usr|

View File

@ -92,4 +92,31 @@ describe Score do
Score.findx(3456, 3456).should == -1
end
it "test shortcut for making scores from connections" do
user1 = FactoryGirl.create(:user)
conn1 = FactoryGirl.create(:connection, user: user1, addr: 0x01020304, locidispid: 5)
user2 = FactoryGirl.create(:user)
conn2 = FactoryGirl.create(:connection, user: user2, addr: 0x11121314, locidispid: 6)
user3 = FactoryGirl.create(:user)
conn3 = FactoryGirl.create(:connection, user: user3, addr: 0x21222324, locidispid: 7)
Score.findx(5, 6).should == -1
Score.findx(6, 5).should == -1
Score.findx(5, 7).should == -1
Score.findx(7, 5).should == -1
Score.findx(6, 7).should == -1
Score.findx(7, 6).should == -1
Score.score_conns(conn1, conn2, 12)
Score.score_conns(conn1, conn3, 13)
Score.score_conns(conn2, conn3, 23)
Score.findx(5, 6).should == 12
Score.findx(6, 5).should == 12
Score.findx(5, 7).should == 13
Score.findx(7, 5).should == 13
Score.findx(6, 7).should == 23
Score.findx(7, 6).should == 23
end
end

View File

@ -9,10 +9,12 @@
var logger = context.JK.logger;
var msg_factory = context.JK.MessageFactory;
var rest = context.JK.Rest();
// Let socket.io know where WebSocketMain.swf is
context.WEB_SOCKET_SWF_LOCATION = "assets/flash/WebSocketMain.swf";
context.JK.JamServer = function (app) {
context.JK.JamServer = function (app, activeElementEvent) {
// uniquely identify the websocket connection
var channelId = null;
@ -50,6 +52,8 @@
var $templateDisconnected = null;
var $currentDisplay = null;
var $self = $(this);
var server = {};
server.socket = {};
server.signedIn = false;
@ -59,7 +63,6 @@
server.socketClosedListeners = [];
server.connected = false;
function heartbeatStateReset() {
lastHeartbeatSentTime = null;
lastHeartbeatAckTime = null;
@ -72,10 +75,6 @@
freezeInteraction = activeElementVotes && ((activeElementVotes.dialog && activeElementVotes.dialog.freezeInteraction === true) || (activeElementVotes.screen && activeElementVotes.screen.freezeInteraction === true));
if (!initialConnect) {
context.JK.CurrentSessionModel.onWebsocketDisconnected(in_error);
}
if (in_error) {
reconnectAttempt = 0;
$currentDisplay = renderDisconnected();
@ -108,11 +107,11 @@
server.reconnecting = true;
var result = app.activeElementEvent('beforeDisconnect');
var result = activeElementEvent('beforeDisconnect');
initiateReconnect(result, in_error);
app.activeElementEvent('afterDisconnect');
activeElementEvent('afterDisconnect');
// notify anyone listening that the socket closed
var len = server.socketClosedListeners.length;
@ -193,14 +192,12 @@
heartbeatAckCheckInterval = context.setInterval(_heartbeatAckCheck, 1000);
lastHeartbeatAckTime = new Date(new Date().getTime() + heartbeatMS); // add a little forgiveness to server for initial heartbeat
connectDeferred.resolve();
app.activeElementEvent('afterConnect', payload);
activeElementEvent('afterConnect', payload);
}
function heartbeatAck(header, payload) {
lastHeartbeatAckTime = new Date();
context.JK.CurrentSessionModel.trackChanges(header, payload);
}
function registerLoginAck() {
@ -272,11 +269,7 @@
// TODO: tell certain elements that we've reconnected
}
else {
// this path is the 'in session' path, where we actually reload the page
context.JK.CurrentSessionModel.leaveCurrentSession()
.always(function () {
window.location.reload();
});
window.location.reload();
}
server.reconnecting = false;
});
@ -455,10 +448,10 @@
}
connectDeferred = new $.Deferred();
channelId = context.JK.generateUUID(); // create a new channel ID for every websocket connection
logger.log("connecting websocket, channel_id: " + channelId);
var uri = context.JK.websocket_gateway_uri + '?channel_id=' + channelId; // Set in index.html.erb.
//var uri = context.gon.websocket_gateway_uri; // Leaving here for now, as we're looking for a better solution.
var uri = context.gon.websocket_gateway_uri + '?channel_id=' + channelId; // Set in index.html.erb.
logger.debug("connecting websocket: " + uri);
server.socket = new context.WebSocket(uri);
server.socket.onopen = server.onOpen;

View File

@ -34,6 +34,7 @@
//= require AAA_Log
//= require globals
//= require AAB_message_factory
//= require jam_rest
//= require AAC_underscore
//= require utils
//= require custom_controls

View File

@ -34,8 +34,8 @@
function StartRecording(recordingId, clients) {
startingSessionState = {};
// we expect all clients to respond within 3 seconds to mimic the reliable UDP layer
startingSessionState.aggegratingStartResultsTimer = setTimeout(timeoutStartRecordingTimer, 3000);
// we expect all clients to respond within 1 seconds to mimic the reliable UDP layer
startingSessionState.aggegratingStartResultsTimer = setTimeout(timeoutStartRecordingTimer, 1000);
startingSessionState.recordingId = recordingId;
startingSessionState.groupedClientTracks = copyClientIds(clients, app.clientId); // we will manipulate this new one
@ -70,8 +70,8 @@
stoppingSessionState = {};
// we expect all clients to respond within 3 seconds to mimic the reliable UDP layer
stoppingSessionState.aggegratingStopResultsTimer = setTimeout(timeoutStopRecordingTimer, 3000);
// we expect all clients to respond within 1 seconds to mimic the reliable UDP layer
stoppingSessionState.aggegratingStopResultsTimer = setTimeout(timeoutStopRecordingTimer, 1000);
stoppingSessionState.recordingId = recordingId;
stoppingSessionState.groupedClientTracks = copyClientIds(clients, app.clientId);
@ -137,14 +137,16 @@
}
function onStopRecording(from, payload) {
logger.debug("received stop recording request from " + from);
logger.debug("received stop recording request from " + from);
// TODO check recordingId, and if currently recording
// we should return success if we are currently recording, or if we were already asked to stop for this recordingId
// this means we should keep a list of the last N recordings that we've seen, rather than just keeping the current
context.JK.JamServer.sendP2PMessage(from, JSON.stringify(p2pMessageFactory.stopRecordingAck(payload.recordingId, true)));
// TODO check recordingId, and if currently recording
// we should return success if we are currently recording, or if we were already asked to stop for this recordingId
// this means we should keep a list of the last N recordings that we've seen, rather than just keeping the current
context.JK.JamServer.sendP2PMessage(from, JSON.stringify(p2pMessageFactory.stopRecordingAck(payload.recordingId, true)));
if(stopRecordingResultCallbackName) {
eval(stopRecordingResultCallbackName).call(this, payload.recordingId, {success:payload.success, reason:payload.reason, detail:from});
}
}
function onStopRecordingAck(from, payload) {

View File

@ -385,6 +385,7 @@
})
.on('stoppedRecording', function(e, data) {
if(data.reason) {
logger.warn("Recording Discarded: ", data);
var reason = data.reason;
var detail = data.detail;

View File

@ -90,8 +90,7 @@
// loop through the tracks to get the instruments
for (j=0; j < participant.tracks.length; j++) {
var track = participant.tracks[j];
logger.debug("Find:Finding instruments. Participant tracks:");
logger.debug(participant.tracks);
logger.debug("Find:Finding instruments. Participant tracks:", participant.tracks);
var inst = '../assets/content/icon_instrument_default24.png';
if (track.instrument_id in instrument_logo_map) {
inst = instrument_logo_map[track.instrument_id];

View File

@ -23,7 +23,9 @@
var participantsEverSeen = {};
var $self = $(this);
function id() {
server.registerOnSocketClosed(onWebsocketDisconnected);
function id() {
return currentSession ? currentSession.id : null;
}
@ -91,6 +93,8 @@
server.registerMessageCallback(context.JK.MessageType.SESSION_JOIN, trackChanges);
server.registerMessageCallback(context.JK.MessageType.SESSION_DEPART, trackChanges);
server.registerMessageCallback(context.JK.MessageType.TRACKS_CHANGED, trackChanges);
server.registerMessageCallback(context.JK.MessageType.HEARTBEAT_ACK, trackChanges);
$(document).trigger('jamkazam.session_started', {session: {id: sessionId}});
})
.fail(function() {
@ -107,12 +111,14 @@
server.unregisterMessageCallback(context.JK.MessageType.SESSION_JOIN, trackChanges);
server.unregisterMessageCallback(context.JK.MessageType.SESSION_DEPART, trackChanges);
server.unregisterMessageCallback(context.JK.MessageType.TRACKS_CHANGED, trackChanges);
server.unregisterMessageCallback(context.JK.MessageType.HEARTBEAT_ACK, trackChanges);
//server.unregisterMessageCallback(context.JK.MessageType.MUSICIAN_SESSION_DEPART, refreshCurrentSession);
// leave the session right away without waiting on REST. Why? If you can't contact the server, or if it takes a long
// time, for that entire duration you'll still be sending voice data to the other users.
// this may be bad if someone decides to badmouth others in the left-session during this time
logger.debug("calling jamClient.LeaveSession for clientId=" + clientId);
console.trace();
logger.debug("performLeaveSession: calling jamClient.LeaveSession for clientId=" + clientId);
client.LeaveSession({ sessionID: currentSessionId });
leaveSessionRest(currentSessionId)
.done(function() {
@ -377,10 +383,11 @@
}
function onWebsocketDisconnected(in_error) {
// kill the streaming of the session immediately
logger.debug("calling jamClient.LeaveSession for clientId=" + clientId);
// kill the streaming of the session immediately
if(currentSessionId) {
logger.debug("onWebsocketDisconnect: calling jamClient.LeaveSession for clientId=" + clientId);
client.LeaveSession({ sessionID: currentSessionId });
}
}
// returns a deferred object
@ -423,7 +430,6 @@
this.getCurrentOrLastSession = function() {
return currentOrLastSession;
};
this.trackChanges = trackChanges;
this.getParticipant = function(clientId) {
return participantsEverSeen[clientId]
};

View File

@ -607,6 +607,49 @@
doneYet();
};
context.JK.initJamClient = function() {
// If no jamClient (when not running in native client)
// create a fake one.
if (!(window.jamClient)) {
var p2pMessageFactory = new JK.FakeJamClientMessages();
window.jamClient = new JK.FakeJamClient(JK.app, p2pMessageFactory);
window.jamClient.SetFakeRecordingImpl(new JK.FakeJamClientRecordings(JK.app, jamClient, p2pMessageFactory));
}
else if(false) { // set to true to time long running bridge calls
var originalJamClient = window.jamClient;
var interceptedJamClient = {};
$.each(Object.keys(originalJamClient), function(i, key) {
if(key.indexOf('(') > -1) {
// this is a method. time it
var jsKey = key.substring(0, key.indexOf('('))
console.log("replacing " + jsKey)
interceptedJamClient[jsKey] = function() {
var original = originalJamClient[key]
var start = new Date();
if(key == "FTUEGetDevices()") {
var returnVal = eval('originalJamClient.FTUEGetDevices(' + arguments[0] + ')');
}
else {
var returnVal = original.apply(originalJamClient, arguments);
}
var time = new Date().getTime() - start.getTime();
if(time >= 0) { // if 0, you'll see ALL bridge calls. If you set it to a higher value, you'll only see calls that are beyond that threshold
console.error(time + "ms jamClient." + jsKey + ' returns=', returnVal);
}
return returnVal;
}
}
else {
// we need to intercept properties... but how?
}
});
window.jamClient = interceptedJamClient;
}
}
context.JK.clientType = function () {
if (context.jamClient) {
return context.jamClient.IsNativeClient() ? 'client' : 'browser';

View File

@ -52,3 +52,8 @@
//= require web/sessions
//= require web/recordings
//= require web/welcome
//= require banner
//= require fakeJamClient
//= require fakeJamClientMessages
//= require fakeJamClientRecordings
//= require JamServer

View File

@ -1,4 +1,6 @@
/**
*= require client/banner
*= require client/jamServer
*= require client/ie
*= require client/jamkazam
*= require easydropdown

View File

@ -7,13 +7,12 @@ class ApiScoringController < ApiController
clientid = params[:clientid]
if clientid.nil? then render :json => {message: 'clientid not specified'}, :status => 400; return end
conn = Connection.where(client_id: clientid).first
conn = Connection.where(client_id: clientid, user_id: current_user.id).first
if conn.nil? then render :json => {message: 'session not found'}, :status => 404; return end
if !current_user.id.eql?(conn.user.id) then render :json => {message: 'session not owned by user'}, :status => 403; return end
# if !current_user.id.eql?(conn.user.id) then render :json => {message: 'session not owned by user'}, :status => 403; return end
# todo this method is a stub
#puts "ApiScoringController#work(#{clientid}) => locidispid #{c.locidispid}"
result_client_id = JamRuby::GetWork.get_work(conn.locidispid)
result_client_id = JamRuby::GetWork.get_work(conn.locidispid, conn.addr)
#result_client_id = clientid+'peer'
render :json => {:clientid => result_client_id}, :status => 200
@ -23,12 +22,11 @@ class ApiScoringController < ApiController
clientid = params[:clientid]
if clientid.nil? then render :json => {message: 'clientid not specified'}, :status => 400; return end
conn = Connection.where(client_id: clientid).first
conn = Connection.where(client_id: clientid, user_id: current_user.id).first
if conn.nil? then render :json => {message: 'session not found'}, :status => 404; return end
if !current_user.id.eql?(conn.user.id) then render :json => {message: 'session not owned by user'}, :status => 403; return end
# if !current_user.id.eql?(conn.user.id) then render :json => {message: 'session not owned by user'}, :status => 403; return end
# todo this method is a stub
result_client_ids = JamRuby::GetWork.get_work_list(conn.locidispid)
result_client_ids = JamRuby::GetWork.get_work_list(conn.locidispid, conn.addr)
#result_client_ids = [clientid+'peer1', clientid+'peer2']
render :json => {:clientids => result_client_ids}, :status => 200
@ -61,10 +59,10 @@ class ApiScoringController < ApiController
if !score.is_a? Numeric then render :json => {message: 'score not valid numeric'}, :status => 400; return end
aconn = Connection.where(client_id: aclientid).first
aconn = Connection.where(client_id: aclientid, user_id: current_user.id).first
if aconn.nil? then render :json => {message: 'a\'s session not found'}, :status => 404; return end
if aAddr != aconn.addr then render :json => {message: 'a\'s session addr does not match aAddr'}, :status => 403; return end
if !current_user.id.eql?(aconn.user.id) then render :json => {message: 'a\'s session not owned by user'}, :status => 403; return end
# if !current_user.id.eql?(aconn.user.id) then render :json => {message: 'a\'s session not found'}, :status => 403; return end
bconn = Connection.where(client_id: bclientid).first
if bconn.nil? then render :json => {message: 'b\'s session not found'}, :status => 404; return end

View File

@ -9,13 +9,14 @@ class ApiSearchController < ApiController
if 1 == params[Search::PARAM_MUSICIAN].to_i || 1 == params[Search::PARAM_BAND].to_i
query = params.clone
query[:remote_ip] = request.remote_ip
if 1 == params[Search::PARAM_MUSICIAN].to_i
@search = Search.musician_filter(query, current_user)
if 1 == query[Search::PARAM_MUSICIAN].to_i
clientid = params[:clientid]
conn = (clientid ? Connection.where(client_id: clientid, user_id: current_user.id).first : nil)
@search = Search.musician_filter(query, current_user, conn)
else
@search = Search.band_filter(query, current_user)
end
respond_with @search, responder: ApiResponder, :status => 200
elsif 1 == params[Search::PARAM_SESSION_INVITE].to_i
@search = Search.session_invite_search(params[:query], current_user)
else

View File

@ -3,10 +3,15 @@ class ApplicationController < ActionController::Base
protect_from_forgery
include ApplicationHelper
include SessionsHelper
include ClientHelper
# inject username/email into bugsnag data
before_bugsnag_notify :add_user_info_to_bugsnag
before_filter do
gon_setup
end
before_filter do
if params[AffiliatePartner::PARAM_REFERRAL].present? && current_user.nil?
if cookies[AffiliatePartner::PARAM_COOKIE].blank?

View File

@ -12,22 +12,6 @@ class ClientsController < ApplicationController
return
end
# use gon to pass variables into javascript
gon.websocket_gateway_uri = Rails.application.config.websocket_gateway_uri
gon.check_for_client_updates = Rails.application.config.check_for_client_updates
gon.fp_apikey = Rails.application.config.filepicker_rails.api_key
gon.fp_upload_dir = Rails.application.config.filepicker_upload_dir
gon.allow_force_native_client = Rails.application.config.allow_force_native_client
# is this the native client or browser?
@nativeClient = is_native_client?
# let javascript have access to the server's opinion if this is a native client
gon.isNativeClient = @nativeClient
gon.use_cached_session_scores = Rails.application.config.use_cached_session_scores
gon.allow_both_find_algos = Rails.application.config.allow_both_find_algos
render :layout => 'client'
end

View File

@ -5,6 +5,8 @@
class SpikesController < ApplicationController
include ClientHelper
def facebook_invite
end
@ -24,4 +26,8 @@ class SpikesController < ApplicationController
def launch_app
render :layout => 'web'
end
def websocket
render :layout => false
end
end

View File

@ -15,4 +15,32 @@ module ClientHelper
is_native_client
end
def gon_setup
gon.root_url = root_url
# use gon to pass variables into javascript
if Rails.env == "development"
# if in development mode, we assume you are running websocket-gateway
# on the same host as you hit your server.
gon.websocket_gateway_uri = "ws://" + request.host + ":6767/websocket";
else
# but in any other mode, just use config
gon.websocket_gateway_uri = Rails.application.config.websocket_gateway_uri
end
gon.check_for_client_updates = Rails.application.config.check_for_client_updates
gon.fp_apikey = Rails.application.config.filepicker_rails.api_key
gon.fp_upload_dir = Rails.application.config.filepicker_upload_dir
gon.allow_force_native_client = Rails.application.config.allow_force_native_client
# is this the native client or browser?
@nativeClient = is_native_client?
# let javascript have access to the server's opinion if this is a native client
gon.isNativeClient = @nativeClient
gon.use_cached_session_scores = Rails.application.config.use_cached_session_scores
gon.allow_both_find_algos = Rails.application.config.allow_both_find_algos
end
end

View File

@ -73,18 +73,7 @@
JK = JK || {};
JK.root_url = "<%= root_url %>"
<% if Rails.env == "development" %>
// if in development mode, we assume you are running websocket-gateway
// on the same host as you hit your server.
JK.websocket_gateway_uri = "ws://" + location.hostname + ":6767/websocket";
<% else %>
// but in any other mode, just trust the config coming through gon
JK.websocket_gateway_uri = gon.websocket_gateway_uri
<% end %>
if (console) { console.log("websocket_gateway_uri:" + JK.websocket_gateway_uri); }
JK.root_url = gon.root_url
// If no trackVolumeObject (when not running in native client)
// create a fake one.
@ -263,49 +252,10 @@
}
JK.app = JK.JamKazam();
var jamServer = new JK.JamServer(JK.app);
var jamServer = new JK.JamServer(JK.app, function(event_type) {JK.app.activeElementEvent(event_type)});
jamServer.initialize();
// If no jamClient (when not running in native client)
// create a fake one.
if (!(window.jamClient)) {
var p2pMessageFactory = new JK.FakeJamClientMessages();
window.jamClient = new JK.FakeJamClient(JK.app, p2pMessageFactory);
window.jamClient.SetFakeRecordingImpl(new JK.FakeJamClientRecordings(JK.app, jamClient, p2pMessageFactory));
}
else if(false) { // set to true to time long running bridge calls
var originalJamClient = window.jamClient;
var interceptedJamClient = {};
$.each(Object.keys(originalJamClient), function(i, key) {
if(key.indexOf('(') > -1) {
// this is a method. time it
var jsKey = key.substring(0, key.indexOf('('))
console.log("replacing " + jsKey)
interceptedJamClient[jsKey] = function() {
var original = originalJamClient[key]
var start = new Date();
if(key == "FTUEGetDevices()") {
var returnVal = eval('originalJamClient.FTUEGetDevices(' + arguments[0] + ')');
}
else {
var returnVal = original.apply(originalJamClient, arguments);
}
var time = new Date().getTime() - start.getTime();
if(time >= 0) { // if 0, you'll see ALL bridge calls. If you set it to a higher value, you'll only see calls that are beyond that threshold
console.error(time + "ms jamClient." + jsKey + ' returns=', returnVal);
}
return returnVal;
}
}
else {
// we need to intercept properties... but how?
}
});
window.jamClient = interceptedJamClient;
}
JK.initJamClient();
// Let's get things rolling...
if (JK.currentUserId) {

View File

@ -70,6 +70,9 @@
<%= render "clients/footer" %>
</div>
<%= render "clients/banner" %>
<%= render "clients/banners/disconnected" %>
<%= render "clients/jamServer" %>
<%= render "clients/invitationDialog" %>
<%= render "users/signupDialog" %>
<%= render "users/signinDialog" %>
@ -103,6 +106,12 @@
<% end %>
JK.app = JK.JamKazam();
var jamServer = new JK.JamServer(JK.app, $.noop);
jamServer.initialize();
// JamServer.connect needs the jamClient to be initialized
JK.initJamClient();
JK.app.initialize({inClient: false, layoutOpts: {layoutFooter: false, sizeOverlayToContent: true}});
var facebookHelper = new JK.FacebookHelper(JK.app);
@ -125,6 +134,15 @@
videoDialog.initialize();
JK.bindHoverEvents();
JK.JamServer.connect() // singleton here defined in JamServer.js
.done(function() {
console.log("websocket connected")
})
.fail(function() {
console.log("websocket failed to connect")
});
})
</script>

View File

@ -0,0 +1,57 @@
<!-- you need this javascript -->
<%= javascript_include_tag "jamServer" %>
<!-- gon is required -->
<%= include_gon %>
<!-- you need these templates -->
<%= render "clients/banner" %>
<%= render "clients/banners/disconnected" %>
<%= render "clients/jamServer" %>
<!-- you need these stylesheets -->
<%= stylesheet_link_tag "client/banner", media: "all" %>
<%= stylesheet_link_tag "client/jamServer", media: "all" %>
<script type="text/javascript">
// you can probably do nothing with this in your own code
function signalActiveElement(event_type) {
// event can be one of:
// * beforeDisconnect
// * afterDisconnect
// * afterConnect
// the purpose of this method is to signal to the active element in the UI that websocket state changed
// and in beforeDisconnect in particular, you can return a 'vote' that let's you affect how a reconnect is handled
// you can safely return null, though
console.log("websocket event:" + event_type);
if(event_type == 'beforeDisconnect') {
return null; // causes a in-place websocket reconnect (as opposed to a full page refresh when connection re-established)
}
// no other event cares about return
}
$(function() {
JK = JK || {};
JK.app = JK.JamKazam();
var jamServer = new JK.JamServer(JK.app, signalActiveElement);
jamServer.initialize();
// now you can register for messages somewhere in your code safely... (not necessarily inline here--just somewhere)
// i.e., you can call: context.JK.JamServer.registerMessageCallback
// JamServer.connect needs the jamClient to be initialized
JK.initJamClient();
JK.JamServer.connect() // singleton here defined in JamServer.js
.done(function() {
console.log("websocket connected") // this is used in /client to signal hide of curtain, and initializing the bulk of logic. maybe not useful...
})
.fail(function() {
console.log("websocket failed to connect") // this is used in /client
});
})
</script>

View File

@ -79,7 +79,7 @@ SampleApp::Application.routes.draw do
# route to spike controller (proof-of-concepts)
match '/facebook_invite', to: 'spikes#facebook_invite'
match '/launch_app', to: 'spikes#launch_app'
match '/websocket', to: 'spikes#websocket'
# junk pages
match '/help', to: 'static_pages#help'

View File

@ -9,15 +9,15 @@ describe ApiScoringController do
MARY_IP_ADDRESS = '75.92.54.210' # 1264334546, 4B.5C.36.D2
MARY_ADDR = 1264334546
MARY_LOCIDISPID = 17192008423
MARY_LOCIDISPID = 1807000004
MIKE_IP_ADDRESS = '173.172.108.1' # 2913758209, AD.AC.6C.01
MIKE_ADDR = 2913758209
MIKE_LOCIDISPID = 17192043640
MIKE_LOCIDISPID = 1539000002
JOHN_IP_ADDRESS = '255.255.1.2' # 4294902018, FF.FF.01.02
JOHN_ADDR = 4294902018
JOHN_LOCIDISPID = 0
JOHN_LOCIDISPID = 98765432
before do
@mary = FactoryGirl.create(:user, first_name: 'mary')
@ -83,8 +83,9 @@ describe ApiScoringController do
response.should be_success
json = JSON.parse(response.body, :symbolize_names => true)
json.length.should == 1
json[:clientid].should_not be_nil
[@mary_client_id, @mike_client_id].should include(json[:clientid])
clientid = json[:clientid]
clientid.should_not be_nil
[@mike_client_id].should include(clientid)
end
it 'try work with mike login and mike' do
@ -93,8 +94,9 @@ describe ApiScoringController do
response.should be_success
json = JSON.parse(response.body, :symbolize_names => true)
json.length.should == 1
json[:clientid].should_not be_nil
[@mary_client_id, @mike_client_id].should include(json[:clientid])
clientid = json[:clientid]
clientid.should_not be_nil
[@mary_client_id].should include(clientid)
end
it 'try work with mary login and mike' do
@ -103,7 +105,7 @@ describe ApiScoringController do
response.should_not be_success
json = JSON.parse(response.body, :symbolize_names => true)
json.length.should == 1
json[:message].should eql('session not owned by user')
json[:message].should eql('session not found')
end
it 'try work with mike login and mary' do
@ -112,7 +114,7 @@ describe ApiScoringController do
response.should_not be_success
json = JSON.parse(response.body, :symbolize_names => true)
json.length.should == 1
json[:message].should eql('session not owned by user')
json[:message].should eql('session not found')
end
end
@ -152,13 +154,11 @@ describe ApiScoringController do
response.should be_success
json = JSON.parse(response.body, :symbolize_names => true)
json.length.should == 1
json[:clientids].should_not be_nil
json[:clientids].should_receive :length
json[:clientids].length == 2
[@mary_client_id, @mike_client_id].should include(json[:clientids][0])
[@mary_client_id, @mike_client_id].should include(json[:clientids][1])
json[:clientids][0].should_not eql(json[:clientids][1])
clientids = json[:clientids]
clientids.should_not be_nil
clientids.should respond_to :length
clientids.length.should == 1
[@mike_client_id].should include(clientids[0])
end
it 'try worklist with mike login and mike' do
@ -167,12 +167,11 @@ describe ApiScoringController do
response.should be_success
json = JSON.parse(response.body, :symbolize_names => true)
json.length.should == 1
json[:clientids].should_not be_nil
json[:clientids].should_receive :length
json[:clientids].length == 2
[@mary_client_id, @mike_client_id].should include(json[:clientids][0])
[@mary_client_id, @mike_client_id].should include(json[:clientids][1])
json[:clientids][0].should_not eql(json[:clientids][1])
clientids = json[:clientids]
clientids.should_not be_nil
clientids.should respond_to :length
clientids.length.should == 1
[@mary_client_id].should include(clientids[0])
end
it 'try worklist with mary login and mike' do
@ -181,7 +180,7 @@ describe ApiScoringController do
response.should_not be_success
json = JSON.parse(response.body, :symbolize_names => true)
json.length.should == 1
json[:message].should eql('session not owned by user')
json[:message].should eql('session not found')
end
end
@ -302,7 +301,7 @@ describe ApiScoringController do
response.should_not be_success
json = JSON.parse(response.body, :symbolize_names => true)
json.length.should == 1
json[:message].should eql('a\'s session not owned by user')
json[:message].should eql('a\'s session not found')
end
it 'record with mary login, mary, mary_addr, mary, mary_addr, score' do
@ -359,12 +358,15 @@ describe ApiScoringController do
json[:message].should eql('b\'s location or isp not found')
end
it 'record with mary login, mary, mary_addr, mike, mike_addr, score' do
it 'record with mary login, mary, mary_addr, mike, mike_addr, score (integer)' do
controller.current_user = @mary
post :record, {:format => 'json', :aclientid => @mary_client_id, :aAddr => MARY_IP_ADDRESS, :bclientid => @mike_client_id, :bAddr => MIKE_IP_ADDRESS, :score => 20}
response.should be_success
json = JSON.parse(response.body, :symbolize_names => true)
json.length.should == 0
score = Score.findx(MARY_LOCIDISPID, MIKE_LOCIDISPID)
score.should_not be_nil
score.should eq(20)
end
it 'record with mary login, mary, mary_addr, mike, mike_addr, score (floating pt)' do
@ -373,6 +375,9 @@ describe ApiScoringController do
response.should be_success
json = JSON.parse(response.body, :symbolize_names => true)
json.length.should == 0
score = Score.findx(MARY_LOCIDISPID, MIKE_LOCIDISPID)
score.should_not be_nil
score.should eq(22)
end
end

View File

@ -23,8 +23,10 @@ describe "Landing", :js => true, :type => :feature, :capybara_feature => true do
end
it "footer links work" do
first('#footer-links a').trigger(:click)
should have_selector('h1', text: 'About Us')
first('#footer-links a', text: 'about').trigger(:click)
page.within_window page.driver.window_handles.last do
should have_selector('h1', text: 'About Us')
end
end
end

View File

@ -1,92 +0,0 @@
require 'spec_helper'
# these tests MUST be idempotent and DO use actual production user accounts on www
www = 'http://www.jamkazam.com'
describe "Production site at #{www}", :test_www => true, :js => true, :type => :feature, :capybara_feature => true do
subject { page }
before(:all) do
Capybara.javascript_driver = :poltergeist
Capybara.current_driver = Capybara.javascript_driver
Capybara.app_host = www
Capybara.run_server = false
Capybara.default_wait_time = 10
end
TestUser = Class.new do
attr_accessor :email, :password, :first_name, :last_name, :id
def initialize(h)
h.each {|k,v| send("#{k}=",v)}
end
alias :to_s :first_name
def name
first_name + ' ' + last_name
end
end
user1 = TestUser.new({ email: 'anthony+jim@jamkazam.com', password: 'j4m!t3st3r', first_name: 'Jim', last_name: 'Smith', id: '68e8eea2-140d-44c1-b711-10d07ce70f96' })
user2 = TestUser.new({ email: 'anthony+john@jamkazam.com', password: 'j4m!t3st3r', first_name: 'John', last_name: 'Jones', id: '5bbcf689-2f73-452d-815a-c4f44e9e7f3e' })
# before(:each) do
# emulate_client
# end
it "is possible for #{user1} to sign in and not get disconnected within 30 seconds" do
in_client(user1) do
sign_in_poltergeist user1
repeat_for(30.seconds) do
expect(page).to_not have_selector('.no-websocket-connection') #looks for reconnect dialog every 1 second
end
end
end
it "is possible for #{user1} and #{user2} to see each other online, and to send messages" do
# this example heavily based on text_message_spec.rb
in_client(user1) do
sign_in_poltergeist(user1)
end
test_message = "#{SecureRandom.uuid} - Hey #{user1}!"
test_response = "#{SecureRandom.uuid} - Hey yourself, #{user2}!"
test_goodbye = "#{SecureRandom.uuid} - OK bye!"
in_client(user2) do
sign_in_poltergeist(user2)
expect(page).to have_xpath(
"//div[@class='friend-name' and @user-id='#{user1.id}']/span[@class='friend-status']",
:text => "Available" )
site_search(user1.name, expand: true)
find("#search-results a[user-id=\"#{user1.id}\"][hoveraction=\"musician\"]", text: user1.name).hover_intent
find('#musician-hover #btnMessage').trigger(:click)
find('h1', text: 'conversation with ' + user1.name)
send_text_message(test_message)
end
in_client(user1) do
expect(page).to have_xpath(
"//div[@class='friend-name' and @user-id='#{user2.id}']/span[@class='friend-status']",
:text => "Available" )
find('#notification #ok-button').trigger(:click)
find('h1', text: 'conversation with ' + user2.name)
find('.previous-message-text', text: test_message)
send_text_message(test_response, close_on_send: true)
end
in_client(user2) do
find('.previous-message-text', text: test_response)
send_text_message(test_goodbye, close_on_send: true)
end
in_client(user1) { sign_out_poltergeist }
in_client(user2) { sign_out_poltergeist }
end
end

View File

@ -117,7 +117,7 @@ describe "Reconnect", :js => true, :type => :feature, :capybara_feature => true
# but.. after a few seconds, it should reconnect on it's own
page.should_not have_selector('h2', text: 'Disconnected from Server')
find('h1', text:'session')
find('div[layout-id="session"] h1', text:'session')
end
end
end

View File

@ -50,7 +50,7 @@ describe "Session Recordings", :js => true, :type => :feature, :capybara_feature
start_recording_with(creator, [joiner1])
in_client(creator) do
visit "/downloads" # kills websocket, looking like an abrupt leave
visit "/request_reset_password" # kills websocket, looking like an abrupt leave
end
in_client(joiner1) do
@ -83,7 +83,7 @@ describe "Session Recordings", :js => true, :type => :feature, :capybara_feature
start_recording_with(creator, [joiner1, joiner2])
in_client(creator) do
visit "/downloads" # kills websocket, looking like an abrupt leave
visit "/request_reset_password" # kills websocket, looking like an abrupt leave
end
in_client(joiner1) do

View File

@ -35,6 +35,7 @@ describe "Musician Search API", :type => :api do
context 'location filtering' do
it "gets no musicians for out of range locations" do
pending 'todo scott this needs to be rewritten using scores'
get_query({:city => 'San Francisco', :distance => 100})
good_response
expect((json['musicians'] || []).count).to be 0

View File

@ -479,4 +479,4 @@ def garbage length
output = ''
length.times { output << special_characters.sample }
output.slice(0, length)
end
end