* merging manifest
This commit is contained in:
commit
5f1ea4c754
|
|
@ -150,4 +150,5 @@ diagnostics.sql
|
|||
user_mods.sql
|
||||
connection_stale_expire.sql
|
||||
rename_chat_messages.sql
|
||||
fix_connection_fields.sql
|
||||
fix_connection_fields.sql
|
||||
session_ratings.sql
|
||||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE music_sessions_user_history ADD COLUMN rating_comment TEXT;
|
||||
|
|
@ -15,7 +15,7 @@ module JamRuby
|
|||
|
||||
batch.did_send(emails)
|
||||
|
||||
mail(:to => emails,
|
||||
mail(:to => emails,
|
||||
:from => batch.from_email,
|
||||
:subject => batch.subject) do |format|
|
||||
format.text
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ module JamRuby
|
|||
VAR_LAST_NAME = '@LASTNAME'
|
||||
|
||||
DEFAULT_SENDER = "noreply@jamkazam.com"
|
||||
BATCH_SIZE = 1000
|
||||
BATCH_SIZE = 5
|
||||
|
||||
BODY_TEMPLATE =<<FOO
|
||||
Hello #{VAR_FIRST_NAME},
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ module JamRuby
|
|||
self.primary_key = 'id'
|
||||
|
||||
attr_accessible :max_concurrent_connections, :session_removed_at, :rating
|
||||
validates_inclusion_of :rating, :in => -1..1, :allow_nil => true
|
||||
|
||||
belongs_to(:user,
|
||||
:class_name => "JamRuby::User",
|
||||
|
|
@ -16,8 +17,13 @@ module JamRuby
|
|||
:class_name => "MusicSessionHistory",
|
||||
:foreign_key => "music_session_id")
|
||||
|
||||
validates_inclusion_of :rating, :in => 0..2, :allow_nil => true
|
||||
after_save :track_user_progression
|
||||
def self.latest_history(client_id)
|
||||
self.where(:client_id => client_id)
|
||||
.order('created_at DESC')
|
||||
.limit(1)
|
||||
.includes(:user)
|
||||
.first
|
||||
end
|
||||
|
||||
def music_session_history
|
||||
@msh ||= JamRuby::MusicSessionHistory.find_by_music_session_id(self.music_session_id)
|
||||
|
|
@ -104,10 +110,23 @@ module JamRuby
|
|||
self.perf_data.try(:uri)
|
||||
end
|
||||
|
||||
def track_user_progression
|
||||
if self.rating == 0
|
||||
user.update_progression_field(:first_good_music_session_at)
|
||||
end
|
||||
def add_rating(rval, comment='')
|
||||
rval = rval.to_i
|
||||
self.rating = rval if 0 != rval
|
||||
self.rating_comment = comment
|
||||
end
|
||||
|
||||
MIN_SESSION_DURATION_RATING = 60
|
||||
|
||||
def should_rate_session?
|
||||
(2 <= music_session_history.unique_users.all.count &&
|
||||
MIN_SESSION_DURATION_RATING < (Time.now - music_session_history.created_at).seconds) ||
|
||||
Rails.env.development?
|
||||
end
|
||||
|
||||
def good_rating?
|
||||
0 < self.rating.to_i
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ describe MusicSessionUserHistory do
|
|||
let(:user_history2) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => some_user) }
|
||||
|
||||
describe "create" do
|
||||
pending
|
||||
it {user_history1.music_session_id.should == music_session.id }
|
||||
it {user_history1.created_at.should_not be_nil }
|
||||
it {user_history1.session_removed_at.should be_nil }
|
||||
|
|
@ -15,28 +16,35 @@ describe MusicSessionUserHistory do
|
|||
|
||||
describe "rating" do
|
||||
|
||||
describe "success" do
|
||||
|
||||
before(:each) do
|
||||
user_history1.update_attribute(:rating ,0)
|
||||
end
|
||||
|
||||
it { user_history1.errors.any?.should be_false}
|
||||
it "success" do
|
||||
user_history1.update_attribute(:rating, 1)
|
||||
expect( user_history1.errors.any? ).to eq(false)
|
||||
end
|
||||
|
||||
describe "out of range" do
|
||||
before(:each) do
|
||||
user_history1.update_attribute(:rating, 3)
|
||||
user_history1.save
|
||||
end
|
||||
it "out of range" do
|
||||
user_history1.rating = 2
|
||||
user_history1.save
|
||||
expect( user_history1.errors.any? ).to eq(true)
|
||||
end
|
||||
|
||||
it { user_history1.errors.any?.should be_true}
|
||||
it 'should rate success' do
|
||||
users = [user_history1, user_history2]
|
||||
Timecop.travel(Time.now + (MusicSessionUserHistory::MIN_SESSION_DURATION_RATING * 1.5).seconds)
|
||||
expect( user_history1.should_rate_session? ).to eq(true)
|
||||
Timecop.return
|
||||
end
|
||||
|
||||
it 'should rate fails' do
|
||||
users = [user_history1]
|
||||
expect( user_history1.should_rate_session? ).to eq(false)
|
||||
users = [user_history1, user_history2]
|
||||
expect( user_history2.should_rate_session? ).to eq(false)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "end_history" do
|
||||
|
||||
pending
|
||||
it "histories created at the same time" do
|
||||
user_history1.reload
|
||||
user_history2.reload
|
||||
|
|
|
|||
2
update
2
update
|
|
@ -17,7 +17,7 @@ pushd pb
|
|||
popd
|
||||
|
||||
echo ""
|
||||
echo "updating database"
|
||||
echo "updating ruby"
|
||||
echo ""
|
||||
pushd ruby
|
||||
bundle update
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -19,6 +19,11 @@
|
|||
join : "Join"
|
||||
};
|
||||
|
||||
var sessionQualityTypes = {
|
||||
good : "Good",
|
||||
poor : "Poor"
|
||||
};
|
||||
|
||||
var invitationTypes = {
|
||||
email : "Email",
|
||||
facebook : "Facebook",
|
||||
|
|
@ -83,6 +88,7 @@
|
|||
audioTest : "AudioTest",
|
||||
sessionCount : "SessionCount",
|
||||
sessionMusicians : "SessionMusicians",
|
||||
sessionQuality : "SessionQuality",
|
||||
invite : "Invite",
|
||||
findSession : "FindSession",
|
||||
friendConnect : "Connect",
|
||||
|
|
@ -174,6 +180,11 @@
|
|||
context.ga('send', 'event', categories.sessionMusicians, joinOrCreate);
|
||||
}
|
||||
|
||||
function trackSessionQuality(goodOrPoor) {
|
||||
assertOneOf(goodOrPoor, sessionQualityTypes);
|
||||
context.ga('send', 'event', categories.sessionQuality, goodOrPoor);
|
||||
}
|
||||
|
||||
function trackServiceInvitations(invitationType, numInvited) {
|
||||
assertOneOf(invitationType, invitationTypes);
|
||||
assertNumber(numInvited);
|
||||
|
|
@ -271,6 +282,7 @@
|
|||
var GA = {};
|
||||
GA.Categories = categories;
|
||||
GA.SessionCreationTypes = sessionCreationTypes;
|
||||
GA.SessionQualityTypes = sessionQualityTypes;
|
||||
GA.InvitationTypes = invitationTypes;
|
||||
GA.FriendConnectTypes = friendConnectTypes;
|
||||
GA.RecordingActions = recordingActions;
|
||||
|
|
@ -281,6 +293,7 @@
|
|||
GA.trackFTUECompletion = trackFTUECompletion;
|
||||
GA.trackSessionCount = trackSessionCount;
|
||||
GA.trackSessionMusicians = trackSessionMusicians;
|
||||
GA.trackSessionQuality = trackSessionQuality;
|
||||
GA.trackServiceInvitations = trackServiceInvitations;
|
||||
GA.trackFindSessions = trackFindSessions;
|
||||
GA.virtualPageView = virtualPageView;
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@
|
|||
$.each(response.musicians, function(index, val) {
|
||||
var instrumentHtml = '';
|
||||
|
||||
musicianHtml += '<tr><td width="50"><a href="#" class="avatar-tiny"><img src="' + context.JK.resolveAvatarUrl(val.photo_url) + '" /></a></td>';
|
||||
musicianHtml += '<td width="75"><a href="#">' + val.name + '</a></td>';
|
||||
musicianHtml += '<tr><td width="50"><a user-id="' + val.id + '" profileaction="musician" class="avatar-tiny"><img src="' + context.JK.resolveAvatarUrl(val.photo_url) + '" /></a></td>';
|
||||
musicianHtml += '<td width="75"><<a user-id="' + val.id + '" profileaction="musician">' + val.name + '</a></td>';
|
||||
|
||||
instrumentHtml = '<td><div class="nowrap">';
|
||||
if (val.instruments) { // @FIXME: edge case for Test user that has no instruments?
|
||||
|
|
@ -75,6 +75,8 @@
|
|||
});
|
||||
|
||||
$(hoverSelector).append('<h2>Band Detail</h2>' + bandHtml);
|
||||
|
||||
context.JK.bindProfileClickEvents(hoverSelector);
|
||||
configureActionButtons(response);
|
||||
})
|
||||
.fail(function(xhr) {
|
||||
|
|
|
|||
|
|
@ -36,19 +36,21 @@
|
|||
followingHtml += '<tr>';
|
||||
}
|
||||
|
||||
var avatarUrl, profilePath;
|
||||
var avatarUrl, attrId, type;
|
||||
|
||||
if (val.type === "band") {
|
||||
avatarUrl = context.JK.resolveBandAvatarUrl(val.photo_url);
|
||||
profilePath = "bandProfile";
|
||||
attrId = "band-id";
|
||||
type = "band";
|
||||
}
|
||||
else {
|
||||
avatarUrl = context.JK.resolveAvatarUrl(val.photo_url);
|
||||
profilePath = "profile";
|
||||
attrId = "user-id";
|
||||
type = "musician";
|
||||
}
|
||||
|
||||
followingHtml += '<td width="24"><a href="#" class="avatar-tiny"><img src="' + avatarUrl + '" /></a></td>';
|
||||
followingHtml += '<td><a href="/client#/' + profilePath + '/' + val.id + '"><strong>' + val.name + '</strong></a></td>';
|
||||
followingHtml += '<td width="24"><a ' + attrId + '="' + val.id + '" profileaction="' + type + '" class="avatar-tiny"><img src="' + avatarUrl + '" /></a></td>';
|
||||
followingHtml += '<td><a ' + attrId + '="' + val.id + '" profileaction="' + type + '"><strong>' + val.name + '</strong></a></td>';
|
||||
|
||||
if (index % 2 > 0) {
|
||||
followingHtml += '</tr>';
|
||||
|
|
@ -76,6 +78,8 @@
|
|||
});
|
||||
|
||||
$(hoverSelector).append('<h2>Fan Detail</h2>' + fanHtml);
|
||||
|
||||
context.JK.bindProfileClickEvents(hoverSelector);
|
||||
configureActionButtons(response);
|
||||
})
|
||||
.fail(function(xhr) {
|
||||
|
|
|
|||
|
|
@ -42,19 +42,21 @@
|
|||
followingHtml += '<tr>';
|
||||
}
|
||||
|
||||
var avatarUrl, profilePath;
|
||||
var avatarUrl, attrId, type;
|
||||
|
||||
if (val.type === "band") {
|
||||
avatarUrl = context.JK.resolveBandAvatarUrl(val.photo_url);
|
||||
profilePath = "bandProfile";
|
||||
attrId = "band-id";
|
||||
type = "band";
|
||||
}
|
||||
else {
|
||||
avatarUrl = context.JK.resolveAvatarUrl(val.photo_url);
|
||||
profilePath = "profile";
|
||||
attrId = "user-id";
|
||||
type = "musician";
|
||||
}
|
||||
|
||||
followingHtml += '<td width="24"><a href="#" class="avatar-tiny"><img src="' + avatarUrl + '" /></a></td>';
|
||||
followingHtml += '<td><a href="/client#/' + profilePath + '/' + val.id + '"><strong>' + val.name + '</strong></a></td>';
|
||||
followingHtml += '<td width="24"><a ' + attrId + '="' + val.id + '" profileaction="' + type + '" class="avatar-tiny"><img src="' + avatarUrl + '" /></a></td>';
|
||||
followingHtml += '<td><a ' + attrId + '="' + val.id + '" profileaction="' + type + '"><strong>' + val.name + '</strong></a></td>';
|
||||
|
||||
if (index % 2 > 0) {
|
||||
followingHtml += '</tr>';
|
||||
|
|
@ -101,6 +103,8 @@
|
|||
});
|
||||
|
||||
$(hoverSelector).append('<h2>Musician Detail</h2>' + musicianHtml);
|
||||
|
||||
context.JK.bindProfileClickEvents(hoverSelector);
|
||||
configureActionButtons(response);
|
||||
})
|
||||
.fail(function(xhr) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,123 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
|
||||
context.JK = context.JK || {};
|
||||
context.JK.RateSessionDialog = function(app) {
|
||||
var logger = context.JK.logger;
|
||||
var dialogId = 'rate-session-dialog';
|
||||
var $scopeSelector = "[layout-id='rate-session-dialog']";
|
||||
var clientId = context.JK.JamServer.clientID;
|
||||
|
||||
function reset() {
|
||||
clientId = context.JK.JamServer.clientID;
|
||||
$('#btn-rate-session-up', $scopeSelector).removeClass('selected');
|
||||
$('#btn-rate-session-down', $scopeSelector).removeClass('selected');
|
||||
$('#txt-rate-session-comment',"[layout-id='rate-session-dialog']").val('');
|
||||
}
|
||||
|
||||
function showDialog() {
|
||||
if (clientId) {
|
||||
reset();
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "/api/participant_histories/"+clientId
|
||||
}).done(function (response) {
|
||||
if (response &&
|
||||
response.hasOwnProperty('should_rate_session') &&
|
||||
true==response['should_rate_session']) {
|
||||
app.layout.showDialog(dialogId);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
app.layout.closeDialog(dialogId);
|
||||
}
|
||||
|
||||
function getRating() {
|
||||
if ($('#btn-rate-session-down', $scopeSelector).hasClass('selected')) {
|
||||
return -1;
|
||||
} else if ($('#btn-rate-session-up', $scopeSelector).hasClass('selected')) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getComment() {
|
||||
return $('#txt-rate-session-comment',"[layout-id='rate-session-dialog']").val();
|
||||
}
|
||||
|
||||
function events() {
|
||||
$('#btn-rate-session-cancel', $scopeSelector).click(function(evt) {
|
||||
closeDialog();
|
||||
});
|
||||
$('#btn-rate-session-up', $scopeSelector).click(function(evt) {
|
||||
if ($(this).hasClass('selected')) {
|
||||
$(this).removeClass('selected')
|
||||
} else {
|
||||
$(this).addClass('selected');
|
||||
}
|
||||
if ($('#btn-rate-session-down').hasClass('selected')) {
|
||||
$('#btn-rate-session-down').removeClass('selected')
|
||||
}
|
||||
return false;
|
||||
});
|
||||
$('#btn-rate-session-down', $scopeSelector).click(function(evt) {
|
||||
if ($(this).hasClass('selected')) {
|
||||
$(this).removeClass('selected')
|
||||
} else {
|
||||
$(this).addClass('selected');
|
||||
}
|
||||
if ($('#btn-rate-session-up').hasClass('selected')) {
|
||||
$('#btn-rate-session-up').removeClass('selected')
|
||||
}
|
||||
return false;
|
||||
});
|
||||
$('#btn-rate-session-send', $scopeSelector).click(function(evt) {
|
||||
var rr = getRating(), cc = getComment();
|
||||
if (0 == rr && 0 == cc.length) {
|
||||
closeDialog();
|
||||
return false;
|
||||
}
|
||||
var url = "/api/participant_histories/"+clientId+"/rating";
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: { rating: getRating(), comment: getComment() }
|
||||
}).done(function (response) {
|
||||
var qq = getRating();
|
||||
if (0 < qq) {
|
||||
context.JK.GA.trackSessionQuality(context.JK.GA.SessionQualityTypes.good);
|
||||
} else if (0 > qq){
|
||||
context.JK.GA.trackSessionQuality(context.JK.GA.SessionQualityTypes.poor);
|
||||
}
|
||||
closeDialog();
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function beforeShow(data) {
|
||||
// confirm user should see dialog
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var dialogBindings = {
|
||||
'beforeShow' : beforeShow,
|
||||
'afterShow' : afterShow
|
||||
};
|
||||
app.bindDialog(dialogId, dialogBindings);
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.showDialog = showDialog;
|
||||
};
|
||||
})(window,jQuery);
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
var playbackControls = null;
|
||||
var promptLeave = false;
|
||||
var backendMixerAlertThrottleTimer = null;
|
||||
var rateSessionDialog = null;
|
||||
|
||||
var rest = context.JK.Rest();
|
||||
|
||||
|
|
@ -1305,15 +1306,27 @@
|
|||
}
|
||||
}
|
||||
|
||||
function bailOut() {
|
||||
promptLeave = false;
|
||||
context.window.location = '/client#/home';
|
||||
}
|
||||
|
||||
function sessionLeave(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
promptLeave = false;
|
||||
context.window.location = '/client#/home';
|
||||
|
||||
rateSession();
|
||||
bailOut();
|
||||
return false;
|
||||
}
|
||||
|
||||
function rateSession() {
|
||||
if (rateSessionDialog === null) {
|
||||
rateSessionDialog = new context.JK.RateSessionDialog(context.JK.app);
|
||||
rateSessionDialog.initialize();
|
||||
}
|
||||
rateSessionDialog.showDialog();
|
||||
return true;
|
||||
}
|
||||
|
||||
function sessionResync(evt) {
|
||||
evt.preventDefault();
|
||||
var response = context.jamClient.SessionAudioResync();
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
$(".landing-comment-scroller").prepend(commentHtml);
|
||||
}
|
||||
|
||||
context.JK.bindProfileClickEvents();
|
||||
context.JK.bindHoverEvents();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
$(".landing-comment-scroller").prepend(commentHtml);
|
||||
}
|
||||
|
||||
context.JK.bindProfileClickEvents();
|
||||
context.JK.bindHoverEvents();
|
||||
}
|
||||
|
||||
|
|
@ -129,7 +130,6 @@
|
|||
$("#btnLike").click(like);
|
||||
|
||||
$playButton.trigger('click');
|
||||
|
||||
pollForUpdates(musicSessionId);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -727,4 +727,26 @@ table.vu td {
|
|||
|
||||
#update-session-invite-musicians {
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.rate-thumbsup {
|
||||
width:64px;
|
||||
height:64px;
|
||||
display:inline-block;
|
||||
background-image:url('/assets/content/icon_thumbsup_big_off.png');
|
||||
}
|
||||
|
||||
.rate-thumbsup.selected {
|
||||
background-image:url('/assets/content/icon_thumbsup_big_on.png');
|
||||
}
|
||||
|
||||
.rate-thumbsdown {
|
||||
width:64px;
|
||||
height:64px;
|
||||
display:inline-block;
|
||||
background-image:url('/assets/content/icon_thumbsdown_big_off.png');
|
||||
}
|
||||
|
||||
.rate-thumbsdown.selected {
|
||||
background-image:url('/assets/content/icon_thumbsdown_big_on.png');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,16 +151,27 @@ class ApiMusicSessionsController < ApiController
|
|||
end
|
||||
|
||||
def participant_rating
|
||||
@history = MusicSessionUserHistory.find(params[:id])
|
||||
@history.rating = params[:rating]
|
||||
@history.save
|
||||
if @history = MusicSessionUserHistory.latest_history(params[:client_id])
|
||||
if request.post?
|
||||
@history.add_rating(params[:rating], params[:comment])
|
||||
@history.save
|
||||
|
||||
if @history.errors.any?
|
||||
response.status = :unprocessable_entity
|
||||
respond_with @history
|
||||
else
|
||||
render :json => {}, :status => :ok
|
||||
if @history.errors.any?
|
||||
response.status = :unprocessable_entity
|
||||
respond_with @history
|
||||
else
|
||||
if @history.good_rating? && @history.user.first_good_music_session_at.nil?
|
||||
@history.user.first_good_music_session_at = Time.now
|
||||
@history.user.save
|
||||
end
|
||||
render :json => {}, :status => :ok
|
||||
end
|
||||
elsif request.get?
|
||||
render :json => { :should_rate_session => @history.should_rate_session? }, :status => :ok
|
||||
end
|
||||
else
|
||||
render :json => { :message => ValidationMessages::SESSION_NOT_FOUND }, :status => 404
|
||||
end
|
||||
end
|
||||
|
||||
def track_index
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
<div class="dialog-overlay-sm" layout="dialog" layout-id="rate-session-dialog" id="rate-session-dialog">
|
||||
<!-- dialog header -->
|
||||
<div class="content-head">
|
||||
<%= image_tag "shared/icon_session.png", {:height => 19, :width => 19, :class => "content-icon"} %>
|
||||
<h1>please rate your session</h1>
|
||||
</div>
|
||||
<div class="dialog-inner">
|
||||
<div class="center">
|
||||
<a id="btn-rate-session-up" class="rate-thumbsup" href="#"></a> <a id="btn-rate-session-down" href="#" class="rate-thumbsdown"></a>
|
||||
<br clear="left"><br>
|
||||
<textarea id="txt-rate-session-comment" class="w80" rows="3" placeholder="Tell us more about what you liked or didn't like..."></textarea>
|
||||
<br><br>
|
||||
<a id="btn-rate-session-send" href="#" class="button-orange">SEND FEEDBACK</a> <a id="btn-rate-session-cancel" href="#" class="button-grey">NOT NOW, THANKS</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end inner -->
|
||||
</div>
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
<%= render "clients/gear/gear_wizard" %>
|
||||
<%= render "terms" %>
|
||||
<%= render "leaveSessionWarning" %>
|
||||
<%= render "rateSession" %>
|
||||
<%= render "alert" %>
|
||||
<%= render "sidebar" %>
|
||||
<%= render "createSession" %>
|
||||
|
|
|
|||
|
|
@ -17,11 +17,13 @@
|
|||
</div>
|
||||
|
||||
<script type="text/template" id="template-landing-comment">
|
||||
<div user-id="{user_id}" hoveraction="{hoverAction}" class="avatar-small mr10">
|
||||
<img src="{avatar_url}" alt="" />
|
||||
<div class="avatar-small mr10">
|
||||
<a user-id="{user_id}" profileaction="{hoverAction}" hoveraction="{hoverAction}">
|
||||
<img src="{avatar_url}" alt="" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="w80 left p10 lightgrey mt10 comment-text">
|
||||
<a user-id="{user_id}" hoveraction="{hoverAction}">{name}</a> {comment}
|
||||
<a user-id="{user_id}" profileaction="{hoverAction}" hoveraction="{hoverAction}">{name}</a> {comment}
|
||||
<br />
|
||||
<div class="f12 grey mt5 comment-timestamp">{timeago}</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -10,16 +10,18 @@
|
|||
<% end %>
|
||||
|
||||
<td>
|
||||
<div user-id="<%= track.musician.id %>" hoveraction="musician" class="avatar-small m0">
|
||||
<% unless track.musician.photo_url.blank? %>
|
||||
<%= image_tag "#{track.musician.photo_url}", {:alt => ""} %>
|
||||
<% else %>
|
||||
<%= image_tag "shared/avatar_generic.png", {:alt => ""} %>
|
||||
<% end %>
|
||||
<div class="avatar-small m0">
|
||||
<a user-id="<%= track.musician.id %>" profileaction="musician" hoveraction="musician">
|
||||
<% unless track.musician.photo_url.blank? %>
|
||||
<%= image_tag "#{track.musician.photo_url}", {:alt => ""} %>
|
||||
<% else %>
|
||||
<%= image_tag "shared/avatar_generic.png", {:alt => ""} %>
|
||||
<% end %>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div user-id="<%= track.musician.id %>" hoveraction="musician" class="lightgrey f15 ml10"><%= track.musician.name %></div>
|
||||
<div user-id="<%= track.musician.id %>" profileaction="musician" hoveraction="musician" class="lightgrey f15 ml10"><%= track.musician.name %></div>
|
||||
</td>
|
||||
<td class="p10">
|
||||
<div class="ml10">
|
||||
|
|
|
|||
|
|
@ -168,7 +168,8 @@ SampleApp::Application.routes.draw do
|
|||
match '/sessions/:id/claimed_recording/:claimed_recording_id/start' => 'api_music_sessions#claimed_recording_start', :via => :post
|
||||
match '/sessions/:id/claimed_recording/:claimed_recording_id/stop' => 'api_music_sessions#claimed_recording_stop', :via => :post
|
||||
|
||||
match '/participant_histories/:id/rating' => 'api_music_sessions#participant_rating', :via => :post
|
||||
match '/participant_histories/:client_id/rating' => 'api_music_sessions#participant_rating', :via => :post
|
||||
match '/participant_histories/:client_id' => 'api_music_sessions#participant_rating', :via => :get
|
||||
|
||||
# genres
|
||||
match '/genres' => 'api_genres#index', :via => :get
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
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
|
||||
|
||||
|
|
@ -656,10 +656,10 @@ describe "Music Session API ", :type => :api do
|
|||
msuh = FactoryGirl.create(:music_session_user_history, :music_session_id => music_session.id, :client_id => client.client_id, :user_id => user.id)
|
||||
msuh.rating.should be_nil
|
||||
login(user)
|
||||
post "/api/participant_histories/#{msuh.id}/rating.json", { :rating => 0 }.to_json, "CONTENT_TYPE" => "application/json"
|
||||
post "/api/participant_histories/#{msuh.client_id}/rating.json", { :rating => 1 }.to_json, "CONTENT_TYPE" => "application/json"
|
||||
last_response.status.should == 200
|
||||
msuh.reload
|
||||
msuh.rating.should == 0
|
||||
msuh.rating.to_i.should == 1
|
||||
end
|
||||
|
||||
it "track sync" do
|
||||
|
|
|
|||
|
|
@ -160,8 +160,9 @@ describe "User Progression", :type => :api do
|
|||
client = FactoryGirl.create(:connection, :user => user)
|
||||
music_session = FactoryGirl.create(:music_session, :creator => user, :description => "My Session")
|
||||
msuh = FactoryGirl.create(:music_session_user_history, :music_session_id => music_session.id, :client_id => client.client_id, :user_id => user.id)
|
||||
expect(msuh).to_not eq(nil)
|
||||
login(user)
|
||||
post "/api/participant_histories/#{msuh.id}/rating.json", { :rating => 0 }.to_json, "CONTENT_TYPE" => "application/json"
|
||||
post "/api/participant_histories/#{msuh.client_id}/rating.json", { :rating => 1 }.to_json, "CONTENT_TYPE" => "application/json"
|
||||
|
||||
user.reload
|
||||
user.first_good_music_session_at.should_not be_nil
|
||||
|
|
|
|||
|
|
@ -162,6 +162,9 @@ bputs "before register capybara"
|
|||
config.filter_run_excluding slow: true unless ENV['RUN_SLOW_TESTS'] == "1" || ENV['SLOW'] == "1" || ENV['ALL_TESTS'] == "1"
|
||||
config.filter_run_excluding aws: true unless ENV['RUN_AWS_TESTS'] == "1" || ENV['AWS'] == "1" || ENV['ALL_TESTS'] == "1"
|
||||
|
||||
# by default, do not run production web tests -- even when "ALL_TESTS" is desired
|
||||
config.filter_run_excluding test_www: true unless ENV['TEST_WWW'] == "1"
|
||||
|
||||
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
|
||||
config.fixture_path = "#{::Rails.root}/spec/fixtures"
|
||||
|
||||
|
|
|
|||
|
|
@ -169,6 +169,15 @@ def wait_to_see_my_track
|
|||
within('div.session-mytracks') {first('div.session-track.track')}
|
||||
end
|
||||
|
||||
def repeat_for(duration=Capybara.default_wait_time)
|
||||
finish_time = Time.now + duration.seconds
|
||||
loop do
|
||||
yield
|
||||
sleep 1 # by default this will execute the block every 1 second
|
||||
break if (Time.now > finish_time)
|
||||
end
|
||||
end
|
||||
|
||||
def determine_test_name(metadata, test_name_buffer = '')
|
||||
description = metadata[:description_args]
|
||||
if description.kind_of?(Array)
|
||||
|
|
@ -430,6 +439,17 @@ def view_band_profile_of band
|
|||
wait_until_curtain_gone
|
||||
end
|
||||
|
||||
def sidebar_search_for string, category
|
||||
visit "/client#/home"
|
||||
find('#search-input')
|
||||
fill_in "search", with: string
|
||||
sleep 1
|
||||
page.execute_script("JK.Sidebar.searchForInput()")
|
||||
wait_for_ajax
|
||||
jk_select(category, "search_text_type")
|
||||
wait_for_ajax
|
||||
end
|
||||
|
||||
def show_user_menu
|
||||
page.execute_script("$('ul.shortcuts').show()")
|
||||
#page.execute_script("JK.UserDropdown.menuHoverIn()")
|
||||
|
|
@ -454,6 +474,5 @@ end
|
|||
def garbage length
|
||||
output = ''
|
||||
length.times { output << special_characters.sample }
|
||||
output.gsub!(/<[\/|!|\?]/, '/<') # security risk -- avoids inputting tags until VRFS-1609 resolved
|
||||
output.slice(0, length)
|
||||
end
|
||||
Loading…
Reference in New Issue