merge conflict

This commit is contained in:
Jonathan Kolyer 2013-10-24 12:29:37 -05:00
commit fec91d1e99
78 changed files with 1719 additions and 643 deletions

View File

@ -73,3 +73,4 @@ crash_dumps.sql
crash_dumps_idx.sql
music_sessions_user_history_add_session_removed_at.sql
user_progress_tracking.sql
whats_next.sql

1
db/up/whats_next.sql Normal file
View File

@ -0,0 +1 @@
ALTER TABLE users ADD COLUMN show_whats_next boolean DEFAULT TRUE;

View File

@ -124,6 +124,7 @@ module JamRuby
validates :terms_of_service, :acceptance => {:accept => true, :on => :create, :allow_nil => false }
validates :subscribe_email, :inclusion => {:in => [nil, true, false]}
validates :musician, :inclusion => {:in => [true, false]}
validates :show_whats_next, :inclusion => {:in => [nil, true, false]}
# custom validators
validate :validate_musician_instruments
@ -651,7 +652,7 @@ module JamRuby
# throws ActiveRecord::RecordNotFound if instrument is invalid
# throws an email delivery error if unable to connect out to SMTP
def self.signup(first_name, last_name, email, password, password_confirmation, terms_of_service, subscribe_email,
def self.signup(first_name, last_name, email, password, password_confirmation, terms_of_service,
location, instruments, birth_date, musician, photo_url, invited_user, signup_confirm_url)
user = User.new
@ -659,7 +660,7 @@ module JamRuby
user.first_name = first_name
user.last_name = last_name
user.email = email
user.subscribe_email = subscribe_email
user.subscribe_email = true
user.terms_of_service = terms_of_service
user.musician = musician

View File

@ -88,7 +88,6 @@ end
gem 'capybara-screenshot'
gem 'cucumber-rails', :require => false #, '1.3.0', :require => false
gem 'factory_girl_rails', '4.1.0'
gem 'database_cleaner', '0.7.0'
gem 'guard-spork', '0.3.2'
gem 'spork', '0.9.0'
gem 'launchy', '2.1.0'

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -91,12 +91,12 @@
function navToEditIdentity() {
resetForm()
window.location = '#/account/identity'
window.location = '/client#/account/identity'
}
function navToEditProfile() {
resetForm()
window.location = '#/account/profile'
window.location = '/client#/account/profile'
}
function navToEditSubscriptions() {
@ -109,7 +109,7 @@
function navToEditAudio() {
resetForm()
window.location = "#/account/audio"
window.location = "/client#/account/audio"
}
// handle update avatar event

View File

@ -74,7 +74,7 @@
function navToAccount() {
resetForm();
window.location = '#/account';
window.location = '/client#/account';
}
function handleUpdateEmail() {

View File

@ -38,7 +38,8 @@
last_name: userDetail.last_name,
user_instruments: userDetail.instruments,
birth_date : userDetail.birth_date,
gender: userDetail.gender
gender: userDetail.gender,
subscribe_email: userDetail.subscribe_email ? "checked=checked" : ""
});
var content_root = $('#account-profile-content-scroller')
@ -263,12 +264,12 @@
function navToAccount() {
resetForm();
window.location = '#/account';
window.location = '/client#/account';
}
function navToAvatar() {
resetForm();
window.location = '#/account/profile/avatar';
window.location = '/client#/account/profile/avatar';
}
function handleUpdateProfile() {
@ -280,11 +281,12 @@
var city = getCityElement().val();
var firstName = getFirstNameElement().val();
var lastName = getLastNameElement().val();
var gender = getGenderElement().val()
var gender = getGenderElement().val();
var subscribeEmail = getSubscribeEmail().is(':checked');
var birthDate = getBirthDate();
var instruments = getInstrumentsValue();
postUpdateProfile({
api.updateUser({
country: country,
state: region,
city: city,
@ -292,25 +294,13 @@
last_name: lastName,
gender: gender,
birth_date: birthDate,
instruments: instruments
instruments: instruments,
subscribe_email: subscribeEmail
})
.done(postUpdateProfileSuccess)
.fail(postUpdateProfileFailure)
}
function postUpdateProfile(options) {
var url = "/api/users/" + context.JK.currentUserId;
return $.ajax({
type: "POST",
dataType: "json",
contentType: 'application/json',
url: url,
data: JSON.stringify(options),
processData: false
});
}
function postUpdateProfileSuccess(response) {
app.notify(
{ title: "Profile Changed",
@ -332,6 +322,7 @@
var city = context.JK.format_errors("city", errors);
var birth_date = context.JK.format_errors("birth_date", errors);
var gender = context.JK.format_errors("birth_date", errors);
var subscribeEmail = context.JK.format_errors("subscribe_email", errors);
var instruments = context.JK.format_errors("musician_instruments", errors)
if(first_name != null) {
@ -358,6 +349,10 @@
getYearElement().closest('div.field').addClass('error').end().after(birth_date);
}
if(subscribeEmail != null) {
getSubscribeEmail().closest('div.field').addClass('error').end().after(subscribeEmail);
}
if(gender != null) {
getGenderElement().closest('div.field').addClass('error').end().after(gender);
}
@ -480,6 +475,10 @@
return $('#account-profile-content-scroller select#user_birth_date_1i');
}
function getSubscribeEmail() {
return $('#account-profile-content-scroller input[name=subscribe_email]');
}
function getInstrumentsElement() {
return $('#account-profile-content-scroller .instrument_selector');
}

View File

@ -15,6 +15,7 @@
var selection = null;
var targetCropSize = 88;
var updatingAvatar = false;
var userDropdown;
function beforeShow(data) {
userId = data.id;
@ -92,7 +93,7 @@
function deleteAvatarSuccess(response) {
renderAvatar(null, null);
JK.UserDropdown.loadMe();
userDropdown.loadMe();
rest.getUserDetail()
.done(function(userDetail) {
@ -139,7 +140,7 @@
function navToEditProfile() {
resetForm();
window.location = '#/account/profile'
window.location = '/client#/account/profile'
}
function renderAvatarSpinner() {
@ -306,8 +307,9 @@
quality: 90,
policy: filepickerPolicy.policy,
signature: filepickerPolicy.signature
}, { path: createStorePath(self.userDetail) + 'cropped.jpg', access: 'public' },
}, { path: createStorePath(self.userDetail) + 'cropped-' + new Date().getTime() + '.jpg', access: 'public' },
function(cropped) {
logger.debug("converting cropped");
rest.getFilepickerPolicy({handle: cropped.url, convert: true})
.done(function(filepickerPolicy) {
filepicker.convert(cropped, {
@ -320,6 +322,7 @@
signature: filepickerPolicy.signature
}, { path: createStorePath(self.userDetail), access: 'public' },
function(scaled) {
logger.debug("converted and scaled final image %o", scaled);
rest.updateAvatar({
original_fpfile: determineCurrentFpfile(),
cropped_fpfile: scaled,
@ -361,7 +364,7 @@
self.userDetail = response;
// notify any listeners that the avatar changed
JK.UserDropdown.loadMe();
userDropdown.loadMe();
// $('.avatar_large img').trigger('avatar_changed', [self.userDetail.photo_url]);
app.notify(
@ -414,13 +417,15 @@
return $.cookie('original_fpfile') == null ? userDetail.crop_selection : null;
}
function initialize() {
function initialize(userDropdownInstance) {
var screenBindings = {
'beforeShow': beforeShow,
'afterShow': afterShow
};
app.bindScreen('account/profile/avatar', screenBindings);
events();
userDropdown = userDropdownInstance;
}
this.initialize = initialize;

View File

@ -12,10 +12,10 @@
//
//= require jquery
//= require jquery_ujs
//= require jquery.icheck
//= require jquery.color
//= require jquery.cookie
//= require jquery.Jcrop
//= require jquery.naturalsize
//= require jquery.queryparams
//= require bootstrap
//= require_directory .

View File

@ -7,7 +7,7 @@
var logger = context.JK.logger;
var realtimeMessaging = context.JK.JamServer;
var friendSelectorDialog = new context.JK.FriendSelectorDialog(app, friendSelectorCallback);
var invitationDialog = new context.JK.InvitationDialog(app);
var invitationDialog = null;
var autoComplete = null;
var userNames = [];
var userIds = [];
@ -100,7 +100,7 @@
}
function resetForm() {
$('#intellectual-property').attr('checked', false);
$('#intellectual-property').iCheck('uncheck').attr('checked', false);
var $form = $('#create-session-form');
var description = sessionSettings.hasOwnProperty('description') ? sessionSettings.description : '';
@ -114,7 +114,7 @@
if (musician_access) {
var approval_required = sessionSettings.hasOwnProperty('approval_required') ? sessionSettings.approval_required : false;
$('#musician-access-option-' + approval_required).attr('checked', 'checked');
$('#musician-access-option-' + approval_required).iCheck('check').attr('checked', 'checked');
}
var fan_access = sessionSettings.hasOwnProperty('fan_access') ? sessionSettings.fan_access : true;
@ -123,7 +123,7 @@
if (fan_access) {
var fan_chat = sessionSettings.hasOwnProperty('fan_chat') ? sessionSettings.fan_chat : false;
$('#fan-chat-option-' + fan_chat).attr('checked', 'checked');
$('#fan-chat-option-' + fan_chat).iCheck('check').attr('checked', 'checked');
}
// Should easily be able to grab other items out of sessionSettings and put them into the appropriate ui elements.
}
@ -293,7 +293,7 @@
friendSelectorDialog.showDialog(selectedFriendIds);
});
$('.btn-email-invitation').click(function() {
$('div[layout-id="createSession"] .btn-email-invitation').click(function() {
invitationDialog.showEmailDialog();
});
@ -374,6 +374,15 @@
resetForm();
}
// this exists solely due to a bug in Windows QTWebkit: https://bugreports.qt-project.org/browse/QTBUG-30072
function initializeButtons() {
$('div[layout-id="createSession"] .icheckbuttons input').iCheck({
checkboxClass: 'icheckbox_minimal',
radioClass: 'iradio_minimal',
inheritClass: true
});
}
function searchFriends(query) {
if (query.length < 2) {
$('#friend-search-results').empty();
@ -403,12 +412,13 @@
});
}
function initialize() {
function initialize(invitationDialogInstance) {
friendSelectorDialog.initialize();
invitationDialog.initialize();
invitationDialog = invitationDialogInstance;
events();
loadBands();
loadSessionSettings();
initializeButtons();
var screenBindings = { 'beforeShow': beforeShow, 'afterShow': afterShow };
app.bindScreen('createSession', screenBindings);
}

View File

@ -106,7 +106,6 @@
$('#btn-send-invitation').show();
$('#btn-next-invitation').hide();
clearTextFields();
app.layout.showDialog('inviteUsers')
}

View File

@ -293,6 +293,21 @@
});
}
function updateUser(options) {
var id = getId(options);
delete options['id'];
return $.ajax({
type: "POST",
dataType: "json",
contentType: 'application/json',
url: "/api/users/" + id,
data: JSON.stringify(options),
processData: false
});
}
function initialize() {
return self;
}
@ -322,6 +337,7 @@
this.userSocialPromoted = userSocialPromoted;
this.createJoinRequest = createJoinRequest;
this.updateJoinRequest = updateJoinRequest;
this.updateUser = updateUser;
return this;
};

View File

@ -30,7 +30,7 @@
var opts = {
inClient: true, // specify false if you want the app object but none of the client-oriented features
layoutOpts: {
layoutFilter: true // specify false if you want footer to be left alone
layoutFooter: true // specify false if you want footer to be left alone
}
};
@ -92,7 +92,6 @@
function loggedIn(header, payload) {
app.clientId = payload.client_id;
$.cookie('client_id', payload.client_id);
// $.cookie('remember_token', payload.token); // removed per vrfs-273/403
heartbeatMS = payload.heartbeat_interval * 1000;
logger.debug("jamkazam.js.loggedIn(): clientId now " + app.clientId + "; Setting up heartbeat every " + heartbeatMS + " MS");

View File

@ -56,6 +56,8 @@
var dialogBindings = {};
var wizardShowFunctions = {};
var openDialogs = []; // FIFO stack
function setup() {
requiredStyles();
hideAll();
@ -284,6 +286,7 @@
if(!opts.layoutFooter) { return; }
var $footer = $('#footer');
$footer.show();
var nHeight = $footer.height();
var footerStyle = {
top: (screenHeight - 80) + 'px'
@ -406,9 +409,11 @@
}
function closeDialog(dialog) {
console.log("closing dialog: " + dialog);
var $dialog = $('[layout-id="' + dialog + '"]');
dialogEvent(dialog, 'beforeHide');
$('.dialog-overlay').hide();
var $overlay = $('.dialog-overlay');
unstackDialogs($overlay);
$dialog.hide();
dialogEvent(dialog, 'afterHide');
}
@ -463,11 +468,47 @@
}
}
/**
* Responsible for keeping N dialogs in correct stacked order,
* also moves the .dialog-overlay such that it hides/obscures all dialogs except the highest one
*/
function stackDialogs($dialog, $overlay) {
console.log("pushing dialog: " + $dialog.attr('layout-id'))
openDialogs.push($dialog);
var zIndex = 1000;
for(var i in openDialogs) {
var $dialog = openDialogs[i];
$dialog.css('zIndex', zIndex);
zIndex++;
}
$overlay.css('zIndex', zIndex - 1);
}
function unstackDialogs($overlay) {
if(openDialogs.length > 0) {
var removed = openDialogs.pop();
console.log("removed dialog : " + removed.attr('layout-id'));
}
else {
console.log("no dialog removed because nothing was on the stack");
}
var zIndex = 1000 + openDialogs.length;
$overlay.css('zIndex', zIndex - 1);
if(openDialogs.length == 0) {
$overlay.hide();
}
}
function showDialog(dialog) {
dialogEvent(dialog, 'beforeShow');
$('.dialog-overlay').show();
var $overlay = $('.dialog-overlay')
$overlay.show();
centerDialog(dialog);
$('[layout-id="' + dialog + '"]').show();
var $dialog = $('[layout-id="' + dialog + '"]');
stackDialogs($dialog, $overlay);
$dialog.show();
dialogEvent(dialog, 'afterShow');
}
@ -547,7 +588,7 @@
this.notify = function(message, descriptor) {
var $notify = $('[layout="notify"]');
if (notifyQueue.length === 0) {
firstNotification = true;
setNotificationInfo(message, descriptor);

View File

@ -440,7 +440,9 @@
addNewGearDialog = new context.JK.AddNewGearDialog(app, ftueCallback);
// # NO LONGER HIDING ADD TRACK even when there are 2 tracks (VRFS-537)
$('#div-add-track').click(function() {
$('#div-add-track').off('click');
$('#div-add-track').on('click', function() {
if (myTracks.length === 2) {
$('#btn-error-ok').click(function() {
app.layout.closeDialog('error-dialog');

View File

@ -6,8 +6,8 @@
context.JK.Sidebar = function(app) {
var logger = context.JK.logger;
var friends = [];
var invitationDialog = new context.JK.InvitationDialog(app);
var rest = context.JK.Rest();
var invitationDialog = null;
function initializeFriendsPanel() {
@ -423,10 +423,12 @@
// watch for Invite More Users events
$('#sidebar-div .btn-email-invitation').click(function() {
invitationDialog.showEmailDialog();
return false;
});
$('#sidebar-div .btn-gmail-invitation').click(function() {
invitationDialog.showGoogleDialog();
return false;
});
}
@ -661,11 +663,12 @@
});
}
this.initialize = function() {
this.initialize = function(invitationDialogInstance) {
events();
initializeFriendsPanel();
initializeChatPanel();
initializeNotificationsPanel();
invitationDialog = invitationDialogInstance;
};
};
})(window,jQuery);

View File

@ -10,7 +10,7 @@
var logger = context.JK.logger;
var rest = new JK.Rest();
var userMe = null;
var invitationDialog = new context.JK.InvitationDialog(app);
var invitationDialog = null;
function menuHoverIn() {
$('ul.shortcuts', this).show();
@ -52,6 +52,7 @@
// TODO - Setting global variable for local user.
context.JK.userMe = r;
updateHeader();
handleWhatsNext(userMe);
}).fail(app.ajaxError);
}
@ -60,6 +61,13 @@
showAvatar();
}
function handleWhatsNext(userProfile) {
if(gon.isNativeClient && userProfile.show_whats_next) {
app.layout.showDialog('whatsNext');
}
}
// initially show avatar
function showAvatar() {
var photoUrl = context.JK.resolveAvatarUrl(userMe.photo_url);
@ -76,10 +84,11 @@
$('#header-avatar').replaceWith(avatar);
}
this.initialize = function() {
this.initialize = function(invitationDialogInstance) {
events();
invitationDialog.initialize();
invitationDialog = invitationDialogInstance;
loadMe();
}
this.loadMe = loadMe;
}
})(window,jQuery);

View File

@ -56,8 +56,17 @@
};
var blurb = $(context._.template($('#client-download-blurb-contents').html(), options, { variable: 'data' }));
// isolate active image for blurb
$('div.hidden-images img[data-purpose=' + platformName + ']', blurb).remove().appendTo($('a.current-os-download', blurb));
var selectOthers = $(context._.template($('#client-download-select-others').html(), options, { variable: 'data' }));
// isolate active images for selectOthers
$('div.hidden-images img[data-purpose=' + platformName1 + ']', selectOthers).remove().appendTo($('a[data-order=1]', selectOthers));
$('div.hidden-images img[data-purpose=' + platformName2 + ']', selectOthers).remove().appendTo($('a[data-order=2]', selectOthers));
// install click handler for change selection
$('a', selectOthers).click(function() {
var platform = $(this).attr('data-platform');

View File

@ -0,0 +1,55 @@
(function(context,$) {
"use strict";
context.JK = context.JK || {};
context.JK.WhatsNextDialog = function(app) {
var logger = context.JK.logger;
var rest = context.JK.Rest();
var invitationDialog = null;
function registerEvents() {
$('#whatsnext-dialog a.facebook-invite').on('click', function(e) {
alert("This feature not yet implemented");
});
$('#whatsnext-dialog a.google-invite').on('click', function(e) {
invitationDialog.showGoogleDialog();
});
$('#whatsnext-dialog a.email-invite').on('click', function(e) {
invitationDialog.showEmailDialog();
});
}
function beforeShow() {
}
function beforeHide() {
var $dontShowWhatsNext = $('#show_whats_next');
if($dontShowWhatsNext.is(':checked')) {
rest.updateUser( {show_whats_next:false})
}
}
function initialize(invitationDialogInstance) {
var dialogBindings = {
'beforeShow' : beforeShow,
'beforeHide': beforeHide
};
app.bindDialog('whatsNext', dialogBindings);
registerEvents();
invitationDialog = invitationDialogInstance;
};
this.initialize = initialize;
}
return this;
})(window,jQuery);

View File

@ -41,12 +41,14 @@
min-width: 165px;
width: 20%;
}
.account-left h2 {
color: #FFFFFF;
font-size: 23px;
font-weight: 400;
margin-bottom: 8px;
}
.account-mid {
float: left;
line-height: 150%;
@ -54,6 +56,29 @@
width: 50%;
}
.account-profile {
padding-top:25px;
h2 {
margin-bottom:15px;
}
.location {
position:relative;
}
#account-change-avatar {
position:absolute;
top:-27px;
right:72px;
height:13px;
}
.birth_date {
margin-left:40px;
}
}
.audio .audio-profiles-short{
white-space: normal;
}

View File

@ -35,4 +35,5 @@
*= require ./banner
*= require ./clientUpdate
*= require jquery.Jcrop
*= require icheck/minimal/minimal
*/

View File

@ -342,7 +342,7 @@ ul.shortcuts {
.tagline {
font-size:30px;
margin-top:55px;
margin-top:35px;
color:#ed3718;
font-weight:300;
width:345px;

View File

@ -29,6 +29,7 @@
.radio-text {
font-size:13px;
line-height:17px;
}
.friendbox {
@ -111,4 +112,20 @@ div.friendbox input[type=text] {
padding:10px;
border-bottom:solid 1px #999;
cursor:pointer;
}
}
div[layout-id="createSession"] .icheckbuttons {
margin-top:5px;
div.iradio_minimal {
float:left;
}
label {
float:left;
margin:0 10px 0 3px;
}
}

View File

@ -9,6 +9,7 @@
padding-top: 10px;
border-top:solid 1px #444;
height:13px;
display:none;
}
#copyright {

View File

@ -299,6 +299,50 @@ div[layout-id="ftue3"] {
border: 1px solid #ed3618;
}
.ftue-overlay.tall {
top:75px;
}
.ftue-overlay.tall .ftue-inner {
padding:5px;
}
#whatsnext-dialog {
height:auto;
.ftue-inner h2 {
font-weight:normal;
color:#ed3618;
margin-bottom:6px;
font-size:1.7em;
}
.ftue-inner table td.whatsnext {
font-size:12px;
padding:10px;
width:50%;
font-weight:300;
}
.ftue-inner table td.whatsnext {
font-size:12px;
padding:10px;
width:50%;
font-weight:300;
}
.ftue-inner table a {
text-decoration:none;
}
.ftue-inner table {
border-collapse:separate;
border-spacing: 20px;
}
}
.ftue-inner {
width:750px;
padding:25px;

View File

@ -131,6 +131,10 @@ input[type="button"] {
font-size:11px;
}
.orange {
color: $ColorScreenPrimary !important;
}
.curtain {
background-color: $ColorScreenBackground;
position:absolute;
@ -433,6 +437,9 @@ input[type="text"], input[type="password"]{
width:100%;
}
.f20 {
font-size: 20px !important;
}
/* TODO - we need a separate stylesheet(s) for signin/signup screens */
/* Following is a style adjustment for the sign-in table spacing */
#sign-in td { padding: 4px; }

View File

@ -175,76 +175,3 @@ strong {
display:block;
}
}
// all custom CSS for the register page goes here
.register-page {
.register-container {
padding:10px;
}
input.register-musician {
}
.error {
padding: 5px 12px 5px 5px;
margin-left:-5px;
margin-right:-12px;
}
input.register-fan {
margin-left:20px;
}
input[type=text], input[type=password] {
margin-top:1px;
width:100%;
}
select {
width:100%;
}
.right-side {
margin-left:25px;
}
.ftue-left {
margin-bottom:30px;
select {
width:104%;
}
div.field {
margin-top:31px;
width:43%;
float:left;
}
}
.ftue-right {
table {
border-collapse:separate;
border-spacing:6px;
}
label.instruments {
margin-bottom:2px;
}
div.field {
margin-top:15px;
}
a.tos {
text-decoration: underline;
}
input[type=submit] {
margin-top:20px;
}
}
}

View File

@ -2,10 +2,9 @@
#footer-container {
position:relative;
width:1100px;
top:20px;
margin:0 6%;
top:100px;
height:13px;
}
#footer {

View File

@ -3,7 +3,6 @@ html {
}
body.web {
background-image: url(../web/bkg_home.gif);
background-repeat: repeat-x;
margin:0 !important;
padding:0 !important;
@ -12,26 +11,12 @@ body.web {
width:auto !important;
#web-container {
padding:3% 6%;
padding:3% 0;
}
div.wrapper {
width: 1100px;
margin: 0 auto;
white-space: nowrap;
}
.logo-home {
width: 298px;
margin-top: 30px;
display: inline-block;
float:left;
}
#profile {
margin-top: 25px;
}
#landing-inner {
p, ul {
color:#999;
line-height:160%;
@ -40,7 +25,153 @@ body.web {
white-space:normal;
font-size:16px;
}
h2 {
font-weight:300;
}
.content-wrapper {
border-bottom: medium none;
padding: 0;
}
.black-bar{
position:relative;
width:100%;
min-height: 366px;
background-color:black;
padding-top:20px;
}
.black-bar-inner {
width:1100px;
margin: 0 auto;
position:relative;
// all custom CSS for the register page goes here
.register-page {
.register-container {
padding:10px;
}
input.register-musician {
}
.actions {
margin-top:20px;
a.button-grey {
line-height:15px; // WHY is this not universal
}
}
.error {
padding: 5px 12px 5px 5px;
margin-left:-5px;
margin-right:-12px;
}
input.register-fan {
margin-left:20px;
}
input[type=text], input[type=password] {
margin-top:1px;
width:100%;
}
select {
width:100%;
}
.right-side {
margin-left:25px;
}
.register-left {
select {
width:104%;
}
div.field {
margin-top:31px;
width:43%;
float:left;
}
}
.register-right {
margin-top:40px;
table {
border-collapse:separate;
border-spacing:6px;
}
label.instruments {
margin-bottom:2px;
}
div.field {
margin-top:15px;
}
a.tos {
text-decoration: underline;
}
.ftue-instrumentlist {
width:100%;
}
}
}
}
.after-black-bar {
position:relative;
background-color:#262626;
width:1100px;
margin:0 auto;
.after-black-bar-inner {
background-color:#262626;
position:absolute;
left:0;
right:0;
}
}
}
.header {
width:1100px;
margin:0 auto;
.logo-home {
width: 298px;
margin-top: 30px;
display: inline-block;
float:left;
}
}
#profile {
position:absolute;
top:-80px;
right:0;
ul {
margin-bottom:0;
}
}
ul {
list-style: none outside none;
}
@ -62,7 +193,7 @@ body.web {
}
.system-requirements {
margin-top:75px;
margin-top:35px;
display:none;
ul {
@ -233,76 +364,3 @@ strong {
display:block;
}
}
// all custom CSS for the register page goes here
.register-page {
.register-container {
padding:10px;
}
input.register-musician {
}
.error {
padding: 5px 12px 5px 5px;
margin-left:-5px;
margin-right:-12px;
}
input.register-fan {
margin-left:20px;
}
input[type=text], input[type=password] {
margin-top:1px;
width:100%;
}
select {
width:100%;
}
.right-side {
margin-left:25px;
}
.ftue-left {
margin-bottom:30px;
select {
width:104%;
}
div.field {
margin-top:31px;
width:43%;
float:left;
}
}
.ftue-right {
table {
border-collapse:separate;
border-spacing:6px;
}
label.instruments {
margin-bottom:2px;
}
div.field {
margin-top:15px;
}
a.tos {
text-decoration: underline;
}
input[type=submit] {
margin-top:20px;
}
}
}

View File

@ -14,14 +14,12 @@ class ApiUsersController < ApiController
respond_to :json
def index
# don't return users that aren't yet confirmed
@users = User.where('email_confirmed=TRUE').paginate(page: params[:page])
@users = User.paginate(page: params[:page])
respond_with @users, responder: ApiResponder, :status => 200
end
def show
# don't return users that aren't yet confirmed
@user = User.where('email_confirmed=TRUE').find(params[:id])
@user = User.find(params[:id])
respond_with @user, responder: ApiResponder, :status => 200
end
@ -65,6 +63,8 @@ class ApiUsersController < ApiController
@user.country = params[:country] if params.has_key?(:country)
@user.musician = params[:musician] if params.has_key?(:musician)
@user.update_instruments(params[:instruments].nil? ? [] : params[:instruments]) if params.has_key?(:instruments)
@user.show_whats_next = params[:show_whats_next] if params.has_key?(:show_whats_next)
@user.subscribe_email = params[:subscribe_email] if params.has_key?(:subscribe_email)
@user.save

View File

@ -3,6 +3,14 @@ class ClientsController < ApplicationController
include UsersHelper
def index
# we want to enforce that /client is always the client view prefix
# this is a side effect of setting root path to '/'; soon we can remove this when we implement the new home page
if request.path == '/'
redirect_to client_url
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
@ -21,6 +29,9 @@ class ClientsController < ApplicationController
end
end
# let javascript have access to the server's opinion if this is a native client
gon.isNativeClient = @nativeClient
if current_user
render :layout => 'client'
else

View File

@ -22,6 +22,11 @@ class UsersController < ApplicationController
end
def new
if current_user
redirect_to :root
return
end
@invited_user = load_invited_user(params)
if !@invited_user.nil? && @invited_user.accepted
@ -41,10 +46,14 @@ class UsersController < ApplicationController
@user.email = @invited_user.email
end
render :layout => 'landing'
render :layout => 'web'
end
def create
if current_user
redirect_to :root
return
end
@invited_user = load_invited_user(params)
@signup_postback = load_postback(@invited_user)
@ -53,7 +62,7 @@ class UsersController < ApplicationController
# check recaptcha; if any errors seen, contribute it to the model
unless verify_recaptcha(:model => @user, :message => "recaptcha")
render 'new', :layout => 'landing'
render 'new', :layout => 'web'
return
end
@ -73,7 +82,6 @@ class UsersController < ApplicationController
params[:jam_ruby_user][:password],
params[:jam_ruby_user][:password_confirmation],
terms_of_service,
subscribe_email,
instruments,
birth_date,
location,
@ -88,7 +96,7 @@ class UsersController < ApplicationController
load_location(request.remote_ip, location)
gon.signup_errors = true
gon.musician_instruments = instruments
render 'new', :layout => 'landing'
render 'new', :layout => 'web'
else
sign_in @user

View File

@ -4,7 +4,7 @@ attributes :id, :first_name, :last_name, :name, :city, :state, :country, :locati
# give back more info if the user being fetched is yourself
if @user == current_user
attributes :email, :original_fpfile, :cropped_fpfile, :crop_selection, :session_settings
attributes :email, :original_fpfile, :cropped_fpfile, :crop_selection, :session_settings, :show_whats_next, :subscribe_email
end
unless @user.friends.nil? || @user.friends.size == 0

View File

@ -22,100 +22,86 @@
<script type="text/template" id="template-account-profile">
<!-- content wrapper -->
<div class="content-wrapper account-profile">
<br />
<form id="account-edit-profile-form">
<table width="100%" cellpadding="0" cellspacing="0">
<tr>
<td valign="top" width="33%"> <!-- TODO -->
<div class="right mr30"><!--<a href="#" class="avatar_large ml10"><img src="images/shared/avatar_jonathon.png" width="246" height="246" /></a>--><br clear="left" />
<a href="#" class="small" id="account-change-avatar">Change Avatar</a></div>
<h2>profile:</h2>
<h2>profile:</h2>
</td>
<div class="location w30 left">
<a href="#" class="small" id="account-change-avatar">Change Avatar</a>
<div class="field">
<label>Country:</label>
<select name='country' class="w80">
<option value='{country}' selected="selected">{country}</option>
</select>
</div>
<div class="field">
<label>State/Province:</label>
<select name='region' class="w80" disabled='disabled'>
<option value="{region}" selected="selected">{region}</option>
</select>
</div>
<div class="field">
<label>City:</label>
<select name='city' class="w80" disabled='disabled'>
<option value="{city}" selected="selected">{city}</option>
</select>
</div>
</div>
<div class="right-side right w70">
<div class="field left w45">
<label>First Name:</label>
<input type="text" name="first_name" value="{first_name}" class="w80"><br/>
</div>
<div class="field right w45">
<label>Last Name:</label>
<input type="text" name="last_name" value="{last_name}" class="w80">
</div>
<br class="clearall"/>
<div class="field left">
<label>Gender:</label>
<select name="gender" data-value="{gender}" class="w80">
<option value='M'>Male</option>
<option value='F'>Female</option>
<option>-</option>
</select>
</div>
<div class="field left birth_date">
<label>Birth Date:</label>
<%= date_select("user", "birth_date", :use_short_month => true, :start_year => 1900, :end_year => Time.now.year - 18, :order => [:month, :day, :year], :default => -25.years.from_now) %>
</div>
<br class="clearall"/>
<td valign="top" width="33%">
<div class="field">
First Name:<br />
<input type="text" name="first_name" value="{first_name}" class="w80"><br />
</div>
</td>
<td valign="top" width="33%">
<div class="field">
Last Name:<br />
<div class="field">
What instruments can you play?
<div class="profile-instrumentlist w90">
<table class="instrument_selector" width="100%" cellpadding="0" cellspacing="6">
<input type="text" name="last_name" value="{last_name}" class="w80">
</div>
</td>
</tr>
<tr>
<td valign="top">
<div class="field">
Country:<br />
<select name='country' class="w80"><option value='{country}' selected="selected">{country}</option></select><br /><br />
</div>
</td>
<td valign="top">
<div class="field">
Gender:<br />
<select name="gender" data-value="{gender}" class="w80"><option value='M'>Male</option><option value='F'>Female</option><option >-</option></select><br />
<br />
</div>
</td>
<td valign="top">
<div class="field">
Birth Date:<br />
<%= date_select("user", "birth_date", :use_short_month => true, :start_year => 1900, :end_year => Time.now.year - 18, :order => [:month, :day, :year], :default => -25.years.from_now ) %>
</div>
</td>
</tr>
<tr>
<td valign="top">
<div class="field">
State/Province:<br />
<select name='region' class="w80" disabled='disabled'><option value="{region}" selected="selected">{region}</option></select><br /><br />
</div>
</td>
<td rowspan=3 colspan=2 valign="top">
<div class="field">
What instruments can you play?
<div class="profile-instrumentlist w90">
<table class="instrument_selector" width="100%" cellpadding="0" cellspacing="6">
</table>
</div>
</div>
</td>
</tr>
<tr>
<td valign="top">
<div class="field">
City:<br />
<select name='city' class="w80" disabled='disabled'><option value="{city}" selected="selected">{city}</option></select><br /><br />
</div>
</td>
</tr>
</table>
</table>
</div>
</div>
<div class="field">
<input type="checkbox" name="subscribe_email" {subscribe_email} /> I will accept email from JamKazam about this service.
</div>
<div class="right actions">
<a id="account-edit-profile-cancel" href="#" class="button-grey">CANCEL</a>&nbsp;&nbsp;<a id="account-edit-profile-submit" href="#" class="button-orange">UPDATE PROFILE</a>
</div>
</div>
</form>
<br clear="all" />
<div class="right"><a id="account-edit-profile-cancel" href="#" class="button-grey">CANCEL</a>&nbsp;&nbsp;<a id="account-edit-profile-submit" href="#" class="button-orange">UPDATE PROFILE</a></div>
<br clear="all"/>
</div>
<!-- end content wrapper -->
@ -125,6 +111,10 @@
<script type="text/template" id="account-profile-instrument">
<tr data-instrument-id='{id}'>
<td><input type="checkbox" {checked} />{description}</td>
<td align="right" width="50%"><select name="proficiency" class='proficiency_selector'><option value="1">Beginner</option><option value="2">Intermediate</option><option value="3">Expert</option></select></td>
<td align="right" width="50%"><select name="proficiency" class='proficiency_selector'>
<option value="1">Beginner</option>
<option value="2">Intermediate</option>
<option value="3">Expert</option>
</select></td>
</tr>
</script>

View File

@ -56,9 +56,9 @@
</select>
</div>
<div class="left">
<input type="radio" name="musician-access-option" id="musician-access-option-false" checked="checked" value="false" />&nbsp;<span class="radio-text">Open</span>&nbsp;&nbsp;
<input type="radio" name="musician-access-option" id="musician-access-option-true" value="true" />&nbsp;<span class="radio-text">By Approval</span>
<div class="left icheckbuttons">
<input type="radio" name="musician-access-option" id="musician-access-option-false" checked="checked" value="false" class="musician-access-false" /><label for="musician-access-option-false" class="radio-text">Open</label>
<input type="radio" name="musician-access-option" id="musician-access-option-true" value="true" class="musician-access-true" /><label for="musician-access-option-true" class="radio-text">By Approval</label>
</div>
</div>
@ -73,9 +73,9 @@
</select>
</div>
<div class="left op50">
<input type="radio" name="fan-chat-option" id="fan-chat-option-true" value="true" disabled="disabled" />&nbsp;<span class="radio-text">Chat</span>&nbsp;&nbsp;
<input type="radio" name="fan-chat-option" id="fan-chat-option-false" checked="checked" value="false" disabled="disabled" />&nbsp;<span class="radio-text">No Fan Chat</span>
<div class="left icheckbuttons">
<input type="radio" name="fan-chat-option" id="fan-chat-option-true" value="true" class="fan-chat-option-true" disabled="disabled" /><label for="fan-chat-option-true" class="radio-text">Chat</label>
<input type="radio" name="fan-chat-option" id="fan-chat-option-false" checked="checked" class="fan-chat-option-false" value="false" disabled="disabled" /><label for="fan-chat-option-false" class="radio-text">No Fan Chat</label>
</div>
</div>
</div>
@ -108,7 +108,7 @@
</div>
<div style="width:78%">
<div class="left mr20">
<div class="left" layout-link="inviteUsers">
<div class="left">
<a class="btn-email-invitation">
<%= image_tag("content/icon_gmail.png", :size => "24x24", :align => "absmiddle") %>
</a>
@ -134,7 +134,7 @@
<div class="right mt5 ml5">Twitter</div>
</div> -->
<div class="left left">
<div class="left" layout-link="inviteUsers">
<div class="left">
<a class="btn-gmail-invitation">
<%= image_tag("content/icon_google.png", :size => "24x24", :align => "absmiddle") %>
</a>
@ -146,8 +146,8 @@
<br clear="all"/>
<!-- terms -->
<div id="divIntellectualProperty">
<div class="terms-checkbox">
<input type="checkbox" id="intellectual-property" />
<div class="terms-checkbox icheckbuttons">
<input type="checkbox" id="intellectual-property" class="intellectual-property" />
</div>
<div id="divTerms" class="terms ml25">
I agree that intellectual property ownership of any musical works created during this session shall be governed by the terms of the <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/" target="_blank">Creative Commons CC BY-NC-SA license</a> in accordance with the <a rel="external" href="http://www.jamkazam.com/corp/terms" target="_blank">JamKazam Terms of Service</a>.

View File

@ -60,7 +60,7 @@
<br clear="all"/>
<div class="invitation-button-holder">
<div class="left mr20">
<div class="left" layout-link="inviteUsers">
<div class="left">
<a class="btn-email-invitation">
<%= image_tag("content/icon_gmail.png", :size => "24x24", :align => "absmiddle") %>
</a>
@ -68,7 +68,7 @@
<div class="right mt5 ml5">E-mail</div>
</div>
<div class="left left">
<div class="left" layout-link="inviteUsers">
<div class="left">
<a class="btn-gmail-invitation">
<%= image_tag("content/icon_google.png", :size => "24x24", :align => "absmiddle") %>
</a>

View File

@ -0,0 +1,70 @@
<!-- Invitation Dialog -->
<div class="dialog whatsnext-overlay ftue-overlay tall" layout="dialog" layout-id="whatsNext" id="whatsnext-dialog">
<div class="content-head">
<h1>what's next?</h1>
</div>
<div class="ftue-inner">
<div align="center">
<table width="790" cellspacing="20">
<tbody>
<tr>
<td valign="top" bgcolor="#000" class="whatsnext">
<h2>INVITE YOUR FRIENDS</h2>
JamKazam is a very new service, so we don't have a bunch of users yet. This will make it
harder to jump into existing sessions with others for a while. So invite other musicians you
know to join using the buttons below, and then schedule a time to meet up (online) and play!<br><br>
<a href="#" class="facebook-invite"><%= image_tag "content/icon_facebook.png", {:align=>"absmiddle", :height => 24, :width => 24} %>&nbsp;Facebook</a>&nbsp;&nbsp;&nbsp;&nbsp;
<a href="#" class="email-invite"><%= image_tag "content/icon_gmail.png", {:align=>"absmiddle", :height => 24, :width => 24} %>&nbsp;E-mail</a>&nbsp;&nbsp;&nbsp;&nbsp;
<a href="#" class="google-invite"><%= image_tag "content/icon_google.png", {:align=>"absmiddle", :height => 26, :width => 26 } %>&nbsp;Google+</a>
</td>
<td valign="top" bgcolor="#000" class="whatsnext">
<h2>FIND MUSICIANS</h2>
<div class="left mr10">
<%= image_tag "content/ftue_whatsnext_musicians.png", {:height => 115, :width => 107 } %>
</div>
Click the Musicians tile on the home screen to find other musicians in your area. Use the
Message button to say hello, or the Connect button to request a friend connection. Then get
a session set up with each other.
</td>
</tr>
<tr>
<td valign="top" bgcolor="#000" class="whatsnext">
<h2>FIND OR CREATE A SESSION</h2>
Click the Find Session tile on the home screen to see if there are any active public
sessions in your area that you can join. If there aren't, use the Create Session tile to
make your own session.<br><br>
<%= image_tag "content/ftue_whatsnext_create.png", {:height => 67, :width => 313 } %>
</td>
<td valign="top" bgcolor="#000" class="whatsnext">
<h2>WATCH VIDEOS</h2>
Watch tuturial videos on YouTube to learn how to use the key features of the JamKazam
service.
<br><br>
<div class="left f20"><br>
<a purpose="youtube-tutorials" rel="external" href="http://www.youtube.com/channel/UC38nc9MMZgExJAd7ca3rkUA" class="orange">See a List of<br>
Videos »</a></div>
<div class="right mr20">
<a purpose="youtube-tutorials" rel="external" href="http://www.youtube.com/channel/UC38nc9MMZgExJAd7ca3rkUA">
<%= image_tag "content/ftue_whatsnext_videos.png", {:height => 90, :width => 152 } %>
</a>
</div>
</td>
</tr>
</tbody>
</table>
<input type="checkbox" id="show_whats_next"> Don't show this again
&nbsp;&nbsp;&nbsp;
<a href="#" class="button-orange" layout-action="close">CLOSE</a><br>
<br>
</div>
</div>
</div>
</div>

View File

@ -30,6 +30,7 @@
<%= render "account_profile_avatar" %>
<%= render "account_audio_profile" %>
<%= render "invitationDialog" %>
<%= render "whatsNextDialog" %>
<%= render "notify" %>
<%= render "client_update" %>
<%= render "banner" %>
@ -86,16 +87,19 @@
// Some things can't be initialized until we're connected. Put them here.
function _initAfterConnect() {
var invitationDialog = new JK.InvitationDialog(JK.app);
invitationDialog.initialize();
var userDropdown = new JK.UserDropdown(JK.app);
JK.UserDropdown = userDropdown;
userDropdown.initialize();
userDropdown.initialize(invitationDialog);
var header = new JK.Header(JK.app);
JK.Header = header;
header.initialize();
var sidebar = new JK.Sidebar(JK.app);
sidebar.initialize();
sidebar.initialize(invitationDialog);
var homeScreen = new JK.HomeScreen(JK.app);
homeScreen.initialize();
@ -113,7 +117,7 @@
accountProfileScreen.initialize();
var accountProfileAvatarScreen = new JK.AccountProfileAvatarScreen(JK.app);
accountProfileAvatarScreen.initialize();
accountProfileAvatarScreen.initialize(userDropdown);
var accountAudioProfile = new JK.AccountAudioProfile(JK.app);
accountAudioProfile.initialize();
@ -126,7 +130,7 @@
JK.Banner.initialize();
var createSessionScreen = new JK.CreateSessionScreen(JK.app);
createSessionScreen.initialize();
createSessionScreen.initialize(invitationDialog);
var findSessionScreen = new JK.FindSessionScreen(JK.app);
var sessionLatency = null;
@ -140,6 +144,10 @@
var sessionSettingsDialog = new JK.SessionSettingsDialog(JK.app, sessionScreen);
sessionSettingsDialog.initialize();
var whatsNextDialog = new JK.WhatsNextDialog(JK.app);
whatsNextDialog.initialize(invitationDialog);
var ftueWizard = new JK.FtueWizard(JK.app);
ftueWizard.initialize();

View File

@ -9,6 +9,7 @@
<!-- THIS NEEDS TO BE IN FRONT OF ANY OTHER JAVASCRIPT INCLUDES ACCORDING TO BUGSNAG -->
<script src="//d2wy8f7a9ursnm.cloudfront.net/bugsnag-1.0.9.min.js" data-apikey="<%= Rails.application.config.bugsnag_key %>"></script>
<% end %>
<%= include_gon(:init => true) %>
<%= javascript_include_tag "corp/corporate" %>
<%= csrf_meta_tags %>
</head>

View File

@ -12,7 +12,7 @@
<!-- THIS NEEDS TO BE IN FRONT OF ANY OTHER JAVASCRIPT INCLUDES ACCORDING TO BUGSNAG -->
<script src="//d2wy8f7a9ursnm.cloudfront.net/bugsnag-1.0.9.min.js" data-apikey="<%= Rails.application.config.bugsnag_key %>"></script>
<% end %>
<%= include_gon %>
<%= include_gon(:init => true) %>
<%= csrf_meta_tags %>
</head>
<body>

View File

@ -12,7 +12,7 @@
<!-- THIS NEEDS TO BE IN FRONT OF ANY OTHER JAVASCRIPT INCLUDES ACCORDING TO BUGSNAG -->
<script src="//d2wy8f7a9ursnm.cloudfront.net/bugsnag-1.0.9.min.js" data-apikey="<%= Rails.application.config.bugsnag_key %>"></script>
<% end %>
<%= include_gon %>
<%= include_gon(:init => true) %>
<%= csrf_meta_tags %>
</head>
<body class="web">
@ -21,52 +21,59 @@
<div id="web-container">
<div class="wrapper">
<div class="wrapper">
<div class="logo-home">
<%= link_to root_path do %>
<%= image_tag("web/logo_home.png", :alt => "JamKazam logo", :size => "298x54") %>
<% end %>
</div>
<%= render "users/user_dropdown" %>
<br clear="all">
<div id="landing-inner">
<%= yield %>
</div>
<div id="footer-container">
<%= render "clients/footer" %>
</div>
</div>
<%= render "clients/invitationDialog" %>
<script type="text/javascript">
$(function () {
JK = JK || {};
<% if current_user %>
JK.currentUserId = '<%= current_user.id %>';
<% else %>
JK.currentUserId = null;
<div class="header">
<div class="logo-home">
<%= link_to root_path do %>
<%= image_tag("web/logo_home.png", :alt => "JamKazam logo", :size => "298x54") %>
<% end %>
</div>
</div>
if (JK.currentUserId) {
JK.app = JK.JamKazam();
JK.app.initialize({inClient: false, layoutOpts: {layoutFooter:false}});
<br clear="all">
var userDropdown = new JK.UserDropdown(JK.app);
userDropdown.initialize();
}
})
</script>
<div class="black-bar">
<div class="black-bar-inner">
<%= render "users/user_dropdown" %>
<%= yield %>
</div>
</div>
<div class="after-black-bar">
<%= yield(:after_black_bar) %>
</div>
<div id="footer-container">
<%= render "clients/footer" %>
</div>
</div>
<%= render "clients/invitationDialog" %>
<script type="text/javascript">
$(function () {
JK = JK || {};
<% if current_user %>
JK.currentUserId = '<%= current_user.id %>';
<% else %>
JK.currentUserId = null;
<% end %>
if (JK.currentUserId) {
JK.app = JK.JamKazam();
JK.app.initialize({inClient: false, layoutOpts: {layoutFooter: false}});
var invitationDialog = new JK.InvitationDialog(JK.app);
invitationDialog.initialize();
var userDropdown = new JK.UserDropdown(JK.app);
userDropdown.initialize(invitationDialog);
}
})
</script>
</div>

View File

@ -18,19 +18,29 @@
</ul>
<br>
{% } %}
<a href="{{data.uri}}" class="current-os-download" data-platform="{{data.platform}}"><%= image_tag("content/button_download_{{data.platformName}}.png", :alt => "download {{data.platformName}}", :size => "348x92") %></a>
<a href="{{data.uri}}" class="current-os-download" data-platform="{{data.platform}}"></a>
<div class="hidden hidden-images">
<%= image_tag("content/button_download_mac.png", :alt => "download mac", :size => "348x92", "data-purpose" => "mac") %>
<%= image_tag("content/button_download_windows.png", :alt => "download windows", :size => "348x92", "data-purpose" => "windows") %>
<%= image_tag("content/button_download_linux.png", :alt => "download linux", :size => "348x92", "data-purpose" => "linux") %>
</div>
</div>
</script>
<script type="text/template" id="client-download-select-others"> 2 1 31 2
<script type="text/template" id="client-download-select-others">
<div class="download-box">
NEED A DIFFERENT VERSION?
<br><br>
<div class="download-others">
<a href="#" data-platform="{{data.platform1}}"><%= image_tag("content/button_download_other_{{data.platformName1}}.png", :alt => "show download for {{data.platformName1}}", :size => "300x79") %></a><br><br>
<a href="#" data-platform="{{data.platform2}}"><%= image_tag("content/button_download_other_{{data.platformName2}}.png", :alt => "show download for {{data.platformName2}}", :size => "300x79") %></a>
<a href="#" data-order="1" data-platform="{{data.platform1}}"></a><br><br>
<a href="#" data-order="2" data-platform="{{data.platform2}}"></a>
</div>
<div class="hidden hidden-images">
<%= image_tag("content/button_download_other_mac.png", :alt => "show download for mac", :size => "300x79", "data-purpose" => "mac") %>
<%= image_tag("content/button_download_other_windows.png", :alt => "show download for windows", :size => "300x79", "data-purpose" => "windows") %>
<%= image_tag("content/button_download_other_linux.png", :alt => "show download for linux", :size => "300x79", "data-purpose" => "linux" ) %>
</div>
</div>
</script>

View File

@ -3,7 +3,7 @@
<div class="w100 ">
<div class="spinner-large"></div>
<div class="w70 left downloads-blurb">
<
</div>
</div>
@ -12,7 +12,7 @@
</div>
<br clear="all">
<% content_for :after_black_bar do %>
<div class="system-requirements w100">
<h3>SYSTEM REQUIREMENTS:</h3><br>
<p>A short summary of requirements follows. For a more detailed explanation of system requirements, please review our <a href="https://jamkazam.desk.com/customer/portal/articles/1288274-minimum-system-requirements">Minimum System Requirements</a> knowledgebase article.</p>
@ -22,14 +22,22 @@
<li>Ethernet port for Internet (we strongly advise that you not use Wi-Fi)</li>
<li>74MB hard disk space for app, plus any space needed for recordings</li>
<li>Audio interface (best to use an audio interface device that gets your music into your computer, else can use built-in mic &amp; headphones on your computer to get started)</li>
<li>Broadband Internet services with 1Mbps uplink bandwidth</li>
<li>Broadband Internet service with 1Mbps uplink bandwidth</li>
</ul>
<ul class="mac-requirements">
<li>Mac</li>
<li>Mac OS X 64-bit operating system 10.7 or higher</li>
<li>Dual-core processor or higher</li>
<li>Ethernet port for Internet (we strongly advise that you not use Wi-Fi)</li>
<li>74MB hard disk space for app, plus any space needed for recordings</li>
<li>Audio interface (best to use an audio interface device that gets your music into your computer, else can use built-in mic &amp; headphones on your computer to get started)</li>
<li>Broadband Internet service with 1Mbps uplink bandwidth</li>
</ul>
<ul class="linux-requirements">
<li>Linux is not yet supported</li>
</ul>
</div>
<%end%>
<%= render "users/download_templates" %>
<%= render "users/download_templates" %>

View File

@ -13,12 +13,12 @@
<div class="arrow-down"></div>
<ul class="shortcuts">
<!-- <li><a layout-link="account">Profile</a></li> -->
<li class="account-home"><%= link_to "Account Home", '/client/#/account' %></li>
<li class="identity"><%= link_to "Identity", '/client/#/account/identity' %></li>
<li class="profile"><%= link_to "Profile", '/client/#/account/profile' %></li>
<!--<li class="subscriptions"><%= link_to "Subscriptions", '/client/#/account/subscriptions' %></li> -->
<!-- <li class="payments"><%= link_to "Payments", '/client/#/account/payments' %></li> -->
<li class="audio"><%= link_to "Audio Gear", '/client/#/account/audio' %></li>
<li class="account-home"><%= link_to "Account Home", '/client#/account' %></li>
<li class="identity"><%= link_to "Identity", '/client#/account/identity' %></li>
<li class="profile"><%= link_to "Profile", '/client#/account/profile' %></li>
<!--<li class="subscriptions"><%= link_to "Subscriptions", '/client#/account/subscriptions' %></li> -->
<!-- <li class="payments"><%= link_to "Payments", '/client#/account/payments' %></li> -->
<li class="audio"><%= link_to "Audio Gear", '/client#/account/audio' %></li>
<li class="invite-friends"><span class='menuheader'><span class="arrow-right"></span><%= link_to "Invite Friends", '#' %></span>
<ul class="shortcuts-submenu">
<li class="google-invite"><%= link_to "Google", '#' %></li>

View File

@ -2,6 +2,8 @@
<div class="tagline">Congratulations!</div>
<p>You have successfully registered as a JamKazam fan.</p>
<div class="proceed"><%= link_to "PROCEED TO JAMKAZAM SITE", root_path, :class =>"button-orange m0" %></div>
<script type="text/javascript">

View File

@ -1,152 +1,155 @@
<% provide(:title, 'Register') %>
<div class="signin-overlay register-page">
<div class="content-head">
<h1>create a jamkazam account</h1>
</div>
<div class="content-wrapper register-page">
<h2>Create a JamKazam account</h2>
<!-- inner wrapper -->
<div class="ftue-inner">
<%= form_for(@user, :url => @signup_postback) do |f| %>
<%= form_for(@user, :url => @signup_postback) do |f| %>
<!-- register left column -->
<div class="ftue-left">
<div class="register-container w100">
Register as a:
<%= f.radio_button :musician, true , :class=> "register-as register-musician"%>
Musician
<!-- register left column -->
<div class="register-left left w45">
<div class="register-container">
<div class="register-as">
Register as a:
<%= f.radio_button :musician, true, :class => "register-as register-musician" %>
Musician
<%= f.radio_button :musician, false, :class=> "register-as register-fan" %>
Fan
<%= f.radio_button :musician, false, :class => "register-as register-fan" %>
Fan
</div>
<div class="field first_name">
<%= f.label :first_name, "First Name:" %>
<%= f.text_field :first_name %>
</div>
<div class="field first_name">
<%= f.label :first_name, "First Name:" %>
<%= f.text_field :first_name %>
</div>
<div class="field last_name right-side">
<%= f.label :last_name, "Last Name:" %>
<%= f.text_field :last_name %>
</div>
<div class="field last_name right-side">
<%= f.label :last_name, "Last Name:" %>
<%= f.text_field :last_name %>
</div>
<br clear="all"/>
<br clear="all"/>
<div class="field email">
<%= f.label :email, "Email Address:" %>
<%= f.text_field :email %>
</div>
<div class="field email">
<%= f.label :email, "Email Address:" %>
<%= f.text_field :email %>
</div>
<div class="field country right-side">
<%= f.label :country, "Country:" %>
<select id="country_select" name="jam_ruby_user[country]" autocomplete="off">
<option value="" <%= @location[:country].blank? ? "selected" : "" %>>Select Country</option>
<% @countries.each do |country| %>
<% unless country.blank? %>
<option value="<%= country %>" <%= @location[:country] == country ? "selected" : "" %>><%= country %></option>
<% end %>
<div class="field country right-side">
<%= f.label :country, "Country:" %>
<select id="country_select" name="jam_ruby_user[country]" autocomplete="off">
<option value="" <%= @location[:country].blank? ? "selected" : "" %>>Select Country</option>
<% @countries.each do |country| %>
<% unless country.blank? %>
<option value="<%= country %>" <%= @location[:country] == country ? "selected" : "" %>><%= country %></option>
<% end %>
</select>
</div>
<% end %>
</select>
</div>
<br clear="all"/>
<br clear="all"/>
<div class="field state">
<%= f.label :state, "State/Province:" %>
<select id="region_select" name="jam_ruby_user[state]" autocomplete="off">
<div class="field state">
<%= f.label :state, "State/Province:" %>
<select id="region_select" name="jam_ruby_user[state]" autocomplete="off">
<option value="" <%= @location[:state].blank? ? "selected" : "" %>>State/Province</option>
<% @regions.each do |region| %>
<% unless region.blank? %>
<option value="<%= region %>" <%= @location[:state] == region ? "selected" : "" %>><%= region %></option>
<option value="<%= region %>" <%= @location[:state] == region ? "selected" : "" %>><%= region %></option>
<% end %>
<% end %>
</select>
</div>
<div class="field city right-side">
<%= f.label :state, "City:" %>
<select id="city_select" name="jam_ruby_user[city]" autocomplete="off">
<option value="" <%= @location[:city].blank? ? "selected" : "" %>>Select City</option>
<% @cities.each do |city| %>
<% unless city.blank? %>
<option value="<%= city %>" <%= @location[:city] == city ? "selected" : "" %>><%= city %></option>
<% end %>
<% end %>
</select>
</div>
<br clear="all"/>
<div class="field password">
<%= f.label :password, "Choose a Password:" %>
<%= f.password_field :password%>
</div>
<div class="field password_confirmation right-side">
<%= f.label :password_confirmation, "Verify Password:" %>
<%= f.password_field :password_confirmation%>
</div>
<br clear="all"/>
</select>
</div>
<div class="field city right-side">
<%= f.label :state, "City:" %>
<select id="city_select" name="jam_ruby_user[city]" autocomplete="off">
<option value="" <%= @location[:city].blank? ? "selected" : "" %>>Select City</option>
<% @cities.each do |city| %>
<% unless city.blank? %>
<option value="<%= city %>" <%= @location[:city] == city ? "selected" : "" %>><%= city %></option>
<% end %>
<% end %>
</select>
</div>
<br clear="all"/>
<div class="field password">
<%= f.label :password, "Choose a Password:" %>
<%= f.password_field :password %>
</div>
<div class="field password_confirmation right-side">
<%= f.label :password_confirmation, "Verify Password:" %>
<%= f.password_field :password_confirmation %>
</div>
<br clear="all"/>
</div>
<!-- end left column -->
</div>
<!-- sign in right column -->
<div class="ftue-right"><br/>
<!-- sign in right column -->
<div class="register-right right w45"><br/>
<div class="ftue-instrumentlist-wrapper">
<label class="instruments">What instruments can you play?</label>
<div class="ftue-instrumentlist">
<table id="instrument_selector" class="instrument_selector" width="100%" cellpadding="0" cellspacing="6">
<% Instrument.standard_list.each do |instrument| %>
<tr>
<td><input id="<%= instrument.id.gsub(" ", "") %>_checkbox" name="jam_ruby_user[instruments][<%= instrument.id %>][selected]" type="checkbox" /><%= instrument.description %></td>
<td align="right" width="50%"><select id="<%= instrument.id.gsub(" ", "") %>_proficiency" name="jam_ruby_user[instruments][<%= instrument.id %>][proficiency]" class='proficiency_selector'><option value="1">Beginner</option><option value="2">Intermediate</option><option value="3">Expert</option></select></td>
</tr>
<% end %>
</table>
</div>
<div class="ftue-instrumentlist-wrapper">
<label class="instruments">What instruments can you play?</label>
<div class="ftue-instrumentlist">
<table id="instrument_selector" class="instrument_selector" width="100%" cellpadding="0" cellspacing="6">
<% Instrument.standard_list.each do |instrument| %>
<tr>
<td>
<input id="<%= instrument.id.gsub(" ", "") %>_checkbox" name="jam_ruby_user[instruments][<%= instrument.id %>][selected]" type="checkbox"/><%= instrument.description %>
</td>
<td align="right" width="50%">
<select id="<%= instrument.id.gsub(" ", "") %>_proficiency" name="jam_ruby_user[instruments][<%= instrument.id %>][proficiency]" class='proficiency_selector'>
<option value="1">Beginner</option>
<option value="2">Intermediate</option>
<option value="3">Expert</option>
</select></td>
</tr>
<% end %>
</table>
</div>
</div>
<div class="field subscribe_email">
<small>
<input id="jam_ruby_user_subscribe_email" name="jam_ruby_user[subscribe_email]" type="checkbox"/>
<span>I will accept email from JamKazam about this service.</span>
</small>
</div>
<div class="field terms_of_service">
<small>
<input id="jam_ruby_user_terms_of_service" name="jam_ruby_user[terms_of_service]" type="checkbox"/>
<span>I have read and agree to the JamKazam <%= link_to "terms of service", corp_terms_path , :rel=>"external" %>.</span>
</small>
</div>
<div class="field terms_of_service">
<small>
<input id="jam_ruby_user_terms_of_service" name="jam_ruby_user[terms_of_service]" type="checkbox"/>
<span>I have read and agree to the JamKazam <%= link_to "terms of service", corp_terms_path, :rel => "external" %>
.</span>
</small>
</div>
<% if Rails.application.config.recaptcha_enable %>
<%= recaptcha_tags %>
<% end %>
<% if Rails.application.config.recaptcha_enable %>
<%= recaptcha_tags %>
<% end %>
<!--
<img src="images/content/captcha.png" width="152" height="50" align="left" class="mr10" /><small>Enter the characters from the box to the left:<br />
<input type="text" /> <br clear="all" /><br />
-->
<!--
<img src="images/content/captcha.png" width="152" height="50" align="left" class="mr10" /><small>Enter the characters from the box to the left:<br />
<input type="text" /> <br clear="all" /><br />
-->
<%= f.submit "CREATE ACCOUNT", class: "right button-orange" %>
<br/ style="clear:both;"><br/>
<!--<a href="/auth/facebook" class="right"><img src="/fb-signup-button.png"></a> -->
<div class="actions">
<%= link_to "CANCEL", root_path, :class=>'button-grey left' %>
<%= f.submit "CREATE ACCOUNT", class: "right button-orange" %>
</div>
<br style="clear:both;"/><br/>
<!--<a href="/auth/facebook" class="right"><img src="/fb-signup-button.png"></a> -->
</div>
</div>
</div>
<!-- end right column -->
<!-- end right column -->
<% end %>
<br clear="all"/>
</div>
<!-- end inner -->
<% end %>
<!-- end overlay content -->
</div>
<!-- end inner -->
<!-- end overlay content -->
@ -157,7 +160,7 @@
window.signup.handle_register_as_changes()
function get_first_error(field) {
if(errors[field] && errors[field].length > 0) {
if (errors[field] && errors[field].length > 0) {
return errors[field][0]
}
else {
@ -166,16 +169,17 @@
}
// populate musician instruments from previous submit, if applicable
if(window.gon && gon.musician_instruments) {
$(gon.musician_instruments).each(function(index, value) {
if (window.gon && gon.musician_instruments) {
$(gon.musician_instruments).each(function (index, value) {
$('#' + value.instrument_id.replace(" ", "") + "_checkbox").attr("checked", true);
$('#' + value.instrument_id.replace(" ", "") + "_proficiency").val(value.proficiency_level.toString())
})
}
// show signup errors, if any
if(window.gon && gon.signup_errors) {
var errors = <%= @user.errors.to_json.html_safe %>
if (window.gon && gon.signup_errors) {
var errors =
<%= @user.errors.to_json.html_safe %>
var email = get_first_error("email")
var first_name = get_first_error("first_name")
@ -189,65 +193,65 @@
var city = get_first_error("city")
if(email) {
if (email) {
var emailInput = $('#jam_ruby_user_email');
emailInput.closest('div.field').addClass('error')
emailInput.after("<div class='error-text'>" + email + "</div>")
}
if(first_name) {
if (first_name) {
var firstNameInput = $('#jam_ruby_user_first_name');
firstNameInput.closest('div.field').addClass('error')
firstNameInput.after("<div class='error-text'>" + first_name + "</div>")
}
if(last_name) {
if (last_name) {
var lastNameInput = $('#jam_ruby_user_last_name');
lastNameInput.closest('div.field').addClass('error')
lastNameInput.after("<div class='error-text'>" + last_name + "</div>")
}
if(country) {
if (country) {
var countryInput = $('#country_select');
countryInput.closest('div.field').addClass('error')
countryInput.after("<div class='error-text'>" + country + "</div>")
}
if(state) {
if (state) {
var stateInput = $('#region_select');
stateInput.closest('div.field').addClass('error')
stateInput.after("<div class='error-text'>" + state + "</div>")
}
if(city) {
if (city) {
var cityInput = $('#city_select');
cityInput.closest('div.field').addClass('error')
cityInput.after("<div class='error-text'>" + city + "</div>")
}
if(musician_instruments) {
if (musician_instruments) {
var musicianInstrumentsInput = $('#instrument_selector');
musicianInstrumentsInput.closest('div.ftue-instrumentlist-wrapper').addClass('error')
musicianInstrumentsInput.closest('div.ftue-instrumentlist').after("<div class='error-text'>" + musician_instruments + "</div>")
}
if(password) {
if (password) {
var passwordInput = $('#jam_ruby_user_password');
passwordInput.closest('div.field').addClass('error')
passwordInput.after("<div class='error-text'>" + password+ "</div>")
passwordInput.after("<div class='error-text'>" + password + "</div>")
}
if(password_confirmation) {
if (password_confirmation) {
var passwordConfirmationInput = $('#jam_ruby_user_password_confirmation');
passwordConfirmationInput.closest('div.field').addClass('error')
passwordConfirmationInput.after("<div class='error-text'>" + password_confirmation + "</div>")
}
if(terms_of_service) {
if (terms_of_service) {
var termsOfServiceInput = $('#jam_ruby_user_terms_of_service');
termsOfServiceInput.closest('small').addClass('error')
// termsOfServiceInput.closest('small').after("<div class='error-text'>" + terms_of_service + "</div>")
// termsOfServiceInput.closest('small').after("<div class='error-text'>" + terms_of_service + "</div>")
}
}

View File

@ -10,7 +10,7 @@ class UserManager < BaseManager
# Note that almost everything can be nil here. This is because when users sign up via social media,
# we don't know much about them.
def signup(remote_ip, first_name, last_name, email, password = nil, password_confirmation = nil, terms_of_service = nil, subscribe_email = nil,
def signup(remote_ip, first_name, last_name, email, password = nil, password_confirmation = nil, terms_of_service = nil,
instruments = nil, birth_date = nil, location = nil, musician = nil, photo_url = nil, invited_user = nil, signup_confirm_url = nil)
@user = User.new
@ -33,7 +33,7 @@ class UserManager < BaseManager
# return @user # @user.errors.any? is true now
#else
# sends email to email account for confirmation
@user = User.signup(first_name, last_name, email, password, password_confirmation, terms_of_service, subscribe_email,
@user = User.signup(first_name, last_name, email, password, password_confirmation, terms_of_service,
location, instruments, birth_date, musician, photo_url, invited_user, signup_confirm_url)
return @user

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

View File

@ -8,11 +8,13 @@ FactoryGirl.define do
password "foobar"
password_confirmation "foobar"
email_confirmed true
show_whats_next = false #annoying for testing, usually
musician true
city "Apex"
state "NC"
country "USA"
terms_of_service true
subscribe_email true
factory :admin do

View File

@ -15,7 +15,7 @@ describe "Account", :js => true, :type => :feature, :capybara_feature => true do
before(:each) do
UserMailer.deliveries.clear
sign_in_poltergeist user
visit "/#/account"
visit "/client#/account"
find('div.account-mid.identity')
end
@ -27,9 +27,11 @@ describe "Account", :js => true, :type => :feature, :capybara_feature => true do
find("#account-edit-identity-link").trigger(:click)
end
it { should have_selector('h2', text: 'identity:' ) }
it { should have_selector('form#account-edit-email-form h4', text: 'Update your email address:') }
it { should have_selector('form#account-edit-password-form h4', text: 'Update your password:') }
it {
should have_selector('h2', text: 'identity:' )
should have_selector('form#account-edit-email-form h4', text: 'Update your email address:')
should have_selector('form#account-edit-password-form h4', text: 'Update your password:')
}
describe "update email" do
@ -43,8 +45,10 @@ describe "Account", :js => true, :type => :feature, :capybara_feature => true do
end
it { should have_selector('h1', text: 'my account') }
it { should have_selector('#notification h2', text: 'Confirmation Email Sent') }
it {
should have_selector('h1', text: 'my account');
should have_selector('#notification h2', text: 'Confirmation Email Sent')
}
end
describe "update password" do
@ -67,10 +71,12 @@ describe "Account", :js => true, :type => :feature, :capybara_feature => true do
find("#account-edit-password-submit").trigger(:click)
end
it { should have_selector('h2', text: 'identity:') }
it { should have_selector('div.field.error input[name=current_password] ~ ul li', text: "can't be blank") }
it { should have_selector('div.field.error input[name=password] ~ ul li', text: "is too short (minimum is 6 characters)") }
it { should have_selector('div.field.error input[name=password_confirmation] ~ ul li', text: "can't be blank") }
it {
should have_selector('h2', text: 'identity:')
should have_selector('div.field.error input[name=current_password] ~ ul li', text: "can't be blank")
should have_selector('div.field.error input[name=password] ~ ul li', text: "is too short (minimum is 6 characters)")
should have_selector('div.field.error input[name=password_confirmation] ~ ul li', text: "can't be blank")
}
end
end
@ -86,11 +92,19 @@ describe "Account", :js => true, :type => :feature, :capybara_feature => true do
before(:each) do
fill_in "first_name", with: "Bobby"
fill_in "last_name", with: "Toes"
find('input[name=subscribe_email]').set(false)
find("#account-edit-profile-submit").trigger(:click)
end
it { should have_selector('h1', text: 'my account') }
it { should have_selector('#notification h2', text: 'Profile Changed') }
it {
user.subscribe_email.should be_true
should have_selector('h1', text: 'my account')
should have_selector('#notification h2', text: 'Profile Changed')
user.reload
user.subscribe_email.should be_false
user.first_name.should == "Bobby"
user.last_name.should == "Toes"
}
end
describe "unsuccessfully" do
@ -101,9 +115,11 @@ describe "Account", :js => true, :type => :feature, :capybara_feature => true do
find("#account-edit-profile-submit").trigger(:click)
end
it { should have_selector('h2', text: 'profile:') }
it { should have_selector('div.field.error input[name=first_name] ~ ul li', text: "can't be blank") }
it { should have_selector('div.field.error input[name=last_name] ~ ul li', text: "can't be blank") }
it {
should have_selector('h2', text: 'profile:')
should have_selector('div.field.error input[name=first_name] ~ ul li', text: "can't be blank")
should have_selector('div.field.error input[name=last_name] ~ ul li', text: "can't be blank")
}
end
end
end

View File

@ -13,8 +13,10 @@ describe "Authentication", :js => true, :type => :feature, :capybara_feature =>
describe "signin page" do
before { visit signin_path }
it { should have_selector('h1', text: 'sign in or register') }
it { page.should have_title("JamKazam | Sign in") }
it {
should have_selector('h1', text: 'sign in or register')
should have_title("JamKazam | Sign in")
}
end
describe "signin" do
@ -23,8 +25,10 @@ describe "Authentication", :js => true, :type => :feature, :capybara_feature =>
describe "with invalid information" do
before { click_button "SIGN IN" }
it { page.should have_title("JamKazam | Sign in") }
it { should have_selector('div.login-error-msg', text: 'Invalid login') }
it {
should have_title("JamKazam | Sign in")
should have_selector('div.login-error-msg', text: 'Invalid login')
}
#describe "after visiting another page" do
#before { click_link "Home" }
@ -42,8 +46,10 @@ describe "Authentication", :js => true, :type => :feature, :capybara_feature =>
end
# Successful sign-in goes to the client
it { page.should have_title("JamKazam") }
it { should have_selector('h2', text: "musicians") }
it {
should have_title("JamKazam")
should have_selector('h2', text: "musicians")
}
describe "signout" do

View File

@ -0,0 +1,33 @@
require 'spec_helper'
describe "Avatar", :js => true, :type => :feature, :capybara_feature => true do
subject { page }
before(:all) do
Capybara.javascript_driver = :poltergeist
Capybara.current_driver = Capybara.javascript_driver
Capybara.default_wait_time = 10
end
let(:user) { FactoryGirl.create(:user) }
before(:each) do
UserMailer.deliveries.clear
sign_in_poltergeist user
visit "/client#/account/profile/avatar"
find('#account-edit-avatar-upload')
end
it {
should have_selector('#account-edit-avatar-upload')
# this causes capybara 1.9.0 and 1.9.2 to crash.
#click_link "UPLOAD" # launch filepicker dialog, which is an iframe
#within_frame('filepicker_dialog') {
# attach_file('fileUpload', 'spec/assets/images/sample_avatar.png')
# find('div.jcrop-tracker').should_not be_nil
#}
}
end

View File

@ -20,9 +20,10 @@ describe "Find Session", :js => true, :type => :feature, :capybara_feature => tr
# when no sessions have been created:
it "shows there are no sessions" do
MusicSession.delete_all
sign_in_poltergeist user
visit "/#/findSession"
# sleep 10
visit "/client#/findSession"
# verify no sessions are found
expect(page).to have_selector('#sessions-none-found')
@ -37,17 +38,15 @@ describe "Find Session", :js => true, :type => :feature, :capybara_feature => tr
in_client(:one) do
page.driver.resize(1500, 600) # crude hack
sign_in_poltergeist user
visit "/#/createSession"
visit "/client#/createSession"
within('#create-session-form') do
fill_in('description', :with => @unique_session_desc)
select('Rock', :from => 'genres')
check('intellectual-property')
find('div.intellectual-property ins').trigger(:click)
click_link('btn-create-session') # fails if page width is low
end
# sleep 10
# verify that the in-session page is showing
expect(page).to have_selector('h2', text: 'my tracks')
end
@ -55,9 +54,7 @@ describe "Find Session", :js => true, :type => :feature, :capybara_feature => tr
# find session in second client
in_client(:two) do
sign_in_poltergeist finder
visit "/#/findSession"
# sleep 10
puts finder.email + " attempting to see session of " + user.email
visit "/client#/findSession"
# verify the session description is seen by second client
expect(page).to have_text(@unique_session_desc)

View File

@ -13,6 +13,19 @@ describe "Home Screen", :js => true, :type => :feature, :capybara_feature => tru
let(:user) { FactoryGirl.create(:user) }
share_examples_for :has_footer do
it "should have footer elements" do
should have_selector('#footer-links')
find('#footer-links').should have_content('about')
find('#footer-links').should have_content('news')
find('#footer-links').should have_content('media')
find('#footer-links').should have_content('contact')
find('#footer-links').should have_content('privacy')
find('#footer-links').should have_content('terms of service')
find('#footer-links').should have_content('help')
end
end
shared_examples_for :go_home do
it "can go back to home" do
find('a.home-icon').trigger(:click)
@ -105,6 +118,7 @@ describe "Home Screen", :js => true, :type => :feature, :capybara_feature => tru
visit "/"
end
it_behaves_like :has_footer
it_behaves_like :create_session_homecard
it_behaves_like :find_session_homecard
it_behaves_like :feed_homecard
@ -122,6 +136,7 @@ describe "Home Screen", :js => true, :type => :feature, :capybara_feature => tru
visit "/"
end
it_behaves_like :has_footer
it_behaves_like :feed_homecard
it_behaves_like :musicians_homecard
it_behaves_like :bands_homecard

View File

@ -10,7 +10,7 @@ describe "Music Session", :js => true, :type => :feature, :capybara_feature => t
within('#create-session-form') do
fill_in('description', :with => 'foobar')
select('Ambient', :from => 'genres')
check('intellectual-property')
find('div.intellectual-property ins').trigger(:click)
click_link('btn-create-session')
end
uu

View File

@ -12,13 +12,13 @@ describe "Signup", :js => true, :type => :feature, :capybara_feature => true do
describe "signup page" do
before { visit signup_path }
it { should have_selector('h1', text: 'create a jamkazam account') }
it { should have_selector('h2', text: 'Create a JamKazam account') }
describe "with valid musician information" do
before do
fill_in "jam_ruby_user[first_name]", with: "Mike"
fill_in "jam_ruby_user[last_name]", with: "Jones"
fill_in "jam_ruby_user[email]", with: "noone@jamkazam.com"
fill_in "jam_ruby_user[email]", with: "newuser1@jamkazam.com"
fill_in "jam_ruby_user[password]", with: "jam123"
fill_in "jam_ruby_user[password_confirmation]", with: "jam123"
check("jam_ruby_user[instruments][drums][selected]")
@ -27,25 +27,29 @@ describe "Signup", :js => true, :type => :feature, :capybara_feature => true do
end
# Successful signup with no invitation tells you to go sign up
it { page.should have_title("JamKazam | Congratulations") }
it { should have_content("You have successfully registered as a JamKazam musician.") }
it { User.find_by_email('noone@jamkazam.com').musician_instruments.length.should == 1 }
# an email is sent on no-invite signup
it { UserMailer.deliveries.length.should == 1 }
it { UserMailer.deliveries[0].html_part.body.include?("To confirm this email address")== 1 }
it {uri = URI.parse(current_url); "#{uri.path}?#{uri.query}".should == congratulations_musician_path(:type => 'Native')}
it {
should have_title("JamKazam | Congratulations")
should have_content("You have successfully registered as a JamKazam musician.")
User.find_by_email('newuser1@jamkazam.com').musician_instruments.length.should == 1
# an email is sent on no-invite signup
UserMailer.deliveries.length.should == 1
UserMailer.deliveries[0].html_part.body.include?("To confirm this email address")== 1
uri = URI.parse(current_url); "#{uri.path}?#{uri.query}".should == congratulations_musician_path(:type => 'Native')
}
describe "user can confirm email and receive welcome email" do
before(:each) do
UserMailer.deliveries.clear
visit signup_confirm_path(User.find_by_email('noone@jamkazam.com').signup_token)
visit signup_confirm_path(User.find_by_email('newuser1@jamkazam.com').signup_token)
end
it { page.should have_title("JamKazam") }
it { should have_selector('h2', text: "musicians") }
it { UserMailer.deliveries.length.should == 1 }
it { UserMailer.deliveries[0].html_part.body.include?("Following are links to some resources")== 1 }
it {
should have_title("JamKazam")
should have_selector('h2', text: "musicians")
UserMailer.deliveries.length.should == 1
UserMailer.deliveries[0].html_part.body.include?("Following are links to some resources")== 1
}
end
end
@ -63,13 +67,16 @@ describe "Signup", :js => true, :type => :feature, :capybara_feature => true do
end
# Successful signup with no invitation tells you to go sign up
it { page.should have_title("JamKazam | Congratulations") }
it { should have_selector('div.tagline', text: "Congratulations!") }
it { should have_selector('a.button-orange.m0', text: 'PROCEED TO JAMKAZAM SITE') }
it { User.find_by_email('somefan@jamkazam.com').musician_instruments.length.should == 0 }
# an email is sent on no-invite signup
it { UserMailer.deliveries.length.should == 1 }
it {uri = URI.parse(current_url); "#{uri.path}?#{uri.query}".should == congratulations_fan_path(:type => 'Native')}
it {
should have_title("JamKazam | Congratulations")
should have_selector('div.tagline', text: "Congratulations!")
should have_selector('a.button-orange.m0', text: 'PROCEED TO JAMKAZAM SITE')
User.find_by_email('somefan@jamkazam.com').musician_instruments.length.should == 0
# an email is sent on no-invite signup
UserMailer.deliveries.length.should == 1
uri = URI.parse(current_url)
"#{uri.path}?#{uri.query}".should == congratulations_fan_path(:type => 'Native')
}
end
describe "with service invite" do
@ -80,7 +87,7 @@ describe "Signup", :js => true, :type => :feature, :capybara_feature => true do
UserMailer.deliveries.clear
fill_in "jam_ruby_user[first_name]", with: "Mike"
fill_in "jam_ruby_user[last_name]", with: "Jones"
fill_in "jam_ruby_user[email]", with: "noone@jamkazam.com"
fill_in "jam_ruby_user[email]", with: "newuser2@jamkazam.com"
fill_in "jam_ruby_user[password]", with: "jam123"
fill_in "jam_ruby_user[password_confirmation]", with: "jam123"
check("jam_ruby_user[instruments][drums][selected]")
@ -89,11 +96,13 @@ describe "Signup", :js => true, :type => :feature, :capybara_feature => true do
end
# Successful sign-in goes to the client
it { page.should have_title("JamKazam") }
it { should have_selector('div.tagline', text: "Congratulations!") }
it { UserMailer.deliveries.length.should == 1 }
it {uri = URI.parse(current_url); "#{uri.path}?#{uri.query}".should == congratulations_musician_path(:type => 'Native')}
it {
should have_title("JamKazam")
should have_selector('div.tagline', text: "Congratulations!")
UserMailer.deliveries.length.should == 1
uri = URI.parse(current_url)
"#{uri.path}?#{uri.query}".should == congratulations_musician_path(:type => 'Native')
}
end
describe "with user invite and autofriend" do
@ -104,7 +113,7 @@ describe "Signup", :js => true, :type => :feature, :capybara_feature => true do
fill_in "jam_ruby_user[first_name]", with: "Mike"
fill_in "jam_ruby_user[last_name]", with: "Jones"
fill_in "jam_ruby_user[email]", with: "noone@jamkazam.com"
fill_in "jam_ruby_user[email]", with: "newuser3@jamkazam.com"
fill_in "jam_ruby_user[password]", with: "jam123"
fill_in "jam_ruby_user[password_confirmation]", with: "jam123"
check("jam_ruby_user[instruments][drums][selected]")
@ -113,11 +122,14 @@ describe "Signup", :js => true, :type => :feature, :capybara_feature => true do
end
# Successful sign-in goes to the client
it { page.should have_title("JamKazam") }
it { should have_selector('div.tagline', text: "Congratulations!") }
it { @user.friends?(User.find_by_email("noone@jamkazam.com")) }
it { User.find_by_email("noone@jamkazam.com").friends?(@user) }
it {uri = URI.parse(current_url); "#{uri.path}?#{uri.query}".should == congratulations_musician_path(:type => 'Native')}
it {
should have_title("JamKazam")
should have_selector('div.tagline', text: "Congratulations!")
@user.friends?(User.find_by_email("newuser3@jamkazam.com"))
User.find_by_email("newuser3@jamkazam.com").friends?(@user)
uri = URI.parse(current_url)
"#{uri.path}?#{uri.query}".should == congratulations_musician_path(:type => 'Native')
}
end
describe "can't signup to the same invite twice" do
@ -127,7 +139,7 @@ describe "Signup", :js => true, :type => :feature, :capybara_feature => true do
fill_in "jam_ruby_user[first_name]", with: "Mike"
fill_in "jam_ruby_user[last_name]", with: "Jones"
fill_in "jam_ruby_user[email]", with: "noone@jamkazam.com"
fill_in "jam_ruby_user[email]", with: "newuser4@jamkazam.com"
fill_in "jam_ruby_user[password]", with: "jam123"
fill_in "jam_ruby_user[password_confirmation]", with: "jam123"
check("jam_ruby_user[instruments][drums][selected]")
@ -135,6 +147,7 @@ describe "Signup", :js => true, :type => :feature, :capybara_feature => true do
click_button "CREATE ACCOUNT"
page.should have_title("JamKazam")
should have_selector('div.tagline', text: "Congratulations!")
sign_out
visit "#{signup_path}?invitation_code=#{@invited_user.invitation_code}"
end
@ -151,7 +164,7 @@ describe "Signup", :js => true, :type => :feature, :capybara_feature => true do
fill_in "jam_ruby_user[first_name]", with: "Mike"
fill_in "jam_ruby_user[last_name]", with: "Jones"
fill_in "jam_ruby_user[email]", with: "noone@jamkazam.com"
fill_in "jam_ruby_user[email]", with: "newuser5@jamkazam.com"
fill_in "jam_ruby_user[password]", with: "jam123"
fill_in "jam_ruby_user[password_confirmation]", with: "jam123"
check("jam_ruby_user[instruments][drums][selected]")
@ -159,14 +172,16 @@ describe "Signup", :js => true, :type => :feature, :capybara_feature => true do
click_button "CREATE ACCOUNT"
end
it { page.should have_title("JamKazam | Congratulations") }
it { should have_content("You have successfully registered as a JamKazam musician.") }
it { User.find_by_email('noone@jamkazam.com').musician_instruments.length.should == 1 }
it { User.find_by_email('what@jamkazam.com').should be_nil }
# an email is sent when you invite but use a different email than the one used to invite
it { UserMailer.deliveries.length.should == 1 }
it {uri = URI.parse(current_url); "#{uri.path}?#{uri.query}".should == congratulations_musician_path(:type => 'Native')}
it {
should have_title("JamKazam | Congratulations")
should have_content("You have successfully registered as a JamKazam musician.")
User.find_by_email('newuser5@jamkazam.com').musician_instruments.length.should == 1
User.find_by_email('what@jamkazam.com').should be_nil
# an email is sent when you invite but use a different email than the one used to invite
UserMailer.deliveries.length.should == 1
uri = URI.parse(current_url)
"#{uri.path}?#{uri.query}".should == congratulations_musician_path(:type => 'Native')
sign_out
visit "#{signup_path}?invitation_code=#{@invited_user.invitation_code}"
should have_selector('h1', text: "You have already signed up with this invitation")
}

View File

@ -27,7 +27,7 @@ describe "User Progression", :js => true, :type => :feature, :capybara_feature
visit signup_path
fill_in "jam_ruby_user[first_name]", with: "Mike"
fill_in "jam_ruby_user[last_name]", with: "Jones"
fill_in "jam_ruby_user[email]", with: "noone@jamkazam.com"
fill_in "jam_ruby_user[email]", with: "user_progression1@jamkazam.com"
fill_in "jam_ruby_user[password]", with: "jam123"
fill_in "jam_ruby_user[password_confirmation]", with: "jam123"
check("jam_ruby_user[instruments][drums][selected]")
@ -44,8 +44,8 @@ describe "User Progression", :js => true, :type => :feature, :capybara_feature
end
it {
User.find_by_email('noone@jamkazam.com').reload();
User.find_by_email('noone@jamkazam.com').first_downloaded_client_at.should_not be_nil
User.find_by_email('user_progression1@jamkazam.com').reload();
User.find_by_email('user_progression1@jamkazam.com').first_downloaded_client_at.should_not be_nil
}
end
@ -73,7 +73,7 @@ describe "User Progression", :js => true, :type => :feature, :capybara_feature
describe "certified gear" do
before(:each) do
sign_in_poltergeist user
visit '/#/account/audio'
visit '/client#/account/audio'
find("div.account-audio a[data-purpose='add-profile']").trigger(:click)
find("a[layout-wizard-link='2']").trigger(:click) # NEXT
find("a[layout-wizard-link='3']").trigger(:click) # NEXT

View File

@ -0,0 +1,74 @@
require 'spec_helper'
describe "Home Screen", :js => true, :type => :feature, :capybara_feature => true do
subject { page }
before(:all) do
Capybara.javascript_driver = :poltergeist
Capybara.current_driver = Capybara.javascript_driver
Capybara.default_wait_time = 10
end
before(:each) do
sign_in_poltergeist user
page.driver.headers = { 'User-Agent' => ' JamKazam ' }
visit "/"
end
let(:user) { FactoryGirl.create(:user, :show_whats_next => true) }
describe "new user in the native view should see the whats next dialog" do
it {
should have_selector('h1', text: 'what\'s next?')
}
describe "open invitation dialog for email" do
before(:each) do
find('#whatsnext-dialog .email-invite').trigger(:click)
end
it {should have_selector('label', text: 'Enter email address(es). If multiple addresses, separate with commas.')}
end
describe "launches youtube tutorial site" do
it {
find("#whatsnext-dialog a.orange[purpose='youtube-tutorials']").trigger(:click)
page.driver.window_handles.last
page.within_window page.driver.window_handles.last do
should have_title('JamKazam - YouTube')
end
}
end
describe "close hides the screen" do
it {
find('#whatsnext-dialog a[layout-action="close"]').trigger(:click)
should have_no_selector('h1', text: 'what\'s next?')
}
end
describe "user can make prompt go away forever" do
it {
find('#show_whats_next').trigger(:click)
find('#whatsnext-dialog a[layout-action="close"]').trigger(:click)
# needed because we poke the server with an updateUser call, but their is no indication in the UI that it's done
wait_for_ajax
page.driver.headers = { 'User-Agent' => ' JamKazam ' }
visit "/"
wait_until_curtain_gone
should_not have_selector('h1', text: 'what\'s next?')
}
end
end
end

View File

@ -20,8 +20,7 @@ describe MusicSessionManager do
it "creates a session properly" do
music_session = @music_session_manager.create(@user, @connection.client_id, "description", true, false, true, true, @band, [@genre], @tracks, true)
MusicSession.count.should == 1
MusicSession.first.id.should == music_session.id
MusicSession.find(music_session.id) # shouldn't throw an exception
end
it "updates a session properly" do
@ -41,10 +40,11 @@ describe MusicSessionManager do
it "deletes a session properly" do
music_session = @music_session_manager.create(@user, @connection.client_id, "description", true, false, true, true, @band, [@genre], @tracks, true)
MusicSessionHistory.count.should == 1
MusicSessionHistory.first.music_session_id.should == music_session.id
music_session_user_history = MusicSessionHistory.find_by_music_session_id(music_session.id)
music_session_user_history.should_not be_nil
music_session.destroy
MusicSessionHistory.first.session_removed_at.should_not == nil
music_session_user_history.reload
music_session_user_history.session_removed_at.should_not == nil
end
end

View File

@ -3,7 +3,6 @@ require 'spec_helper'
# these tests avoid the use of ActiveRecord and FactoryGirl to do blackbox, non test-instrumented tests
describe UserManager do
before(:each) do
@user_manager = UserManager.new(:conn => @conn)
UserMailer.deliveries.clear
@ -13,24 +12,28 @@ describe UserManager do
describe "signup" do
it "signup successfully" do
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "bob@jamkazam.com", "foobar", "foobar", true, nil, @instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm" )
MaxMindIsp.delete_all # prove that city/state/country will remain nil if no maxmind data
MaxMindGeo.delete_all
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "userman1@jamkazam.com", "foobar", "foobar", true, @instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm" )
@user.errors.any?.should be_false
@user.first_name.should == "bob"
@user.last_name.should == "smith"
@user.email.should == "bob@jamkazam.com"
@user.email.should == "userman1@jamkazam.com"
@user.email_confirmed.should be_false
@user.city.should be_nil
@user.state.should be_nil
@user.country.should be_nil
@user.instruments.length.should == 1
@user.subscribe_email.should be_true
@user.signup_token.should_not be_nil
UserMailer.deliveries.length.should == 1
end
it "signup successfully with instruments" do
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "bob@jamkazam.com", "foobar", "foobar", true, nil,
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "userman2@jamkazam.com", "foobar", "foobar", true,
@instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm")
@user.errors.any?.should be_false
@ -41,7 +44,7 @@ describe UserManager do
end
it "doesnt fail if ip address is nil" do
@user = @user_manager.signup(nil, "bob", "smith", "bob@jamkazam.com", "foobar", "foobar", true, nil, @instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm" )
@user = @user_manager.signup(nil, "bob", "smith", "userman3@jamkazam.com", "foobar", "foobar", true, @instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm" )
@user.errors.any?.should be_false
@user.city.should be_nil
@ -53,7 +56,7 @@ describe UserManager do
MaxMindManager.active_record_transaction do |manager|
manager.create_phony_database()
end
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "bob@jamkazam.com", "foobar", "foobar", true, nil, @instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm" )
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "userman4@jamkazam.com", "foobar", "foobar", true, @instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm" )
@user.errors.any?.should be_false
@user.city.should == 'City 127'
@ -65,7 +68,7 @@ describe UserManager do
MaxMindManager.active_record_transaction do |manager|
manager.create_phony_database()
end
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "bob@jamkazam.com", "foobar", "foobar", true, nil, @instruments, nil, @location, true, nil, nil, "http://localhost:3000/confirm" )
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "userman5@jamkazam.com", "foobar", "foobar", true, @instruments, nil, @location, true, nil, nil, "http://localhost:3000/confirm" )
@user.errors.any?.should be_false
@user.city.should == 'Little Rock'
@ -77,7 +80,7 @@ describe UserManager do
MaxMindManager.active_record_transaction do |manager|
manager.create_phony_database()
end
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "bob@jamkazam.com", "foobar", "foobar", true, nil, @instruments, nil, {}, true, nil, nil, "http://localhost:3000/confirm" )
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "userman6@jamkazam.com", "foobar", "foobar", true, @instruments, nil, {}, true, nil, nil, "http://localhost:3000/confirm" )
@user.errors.any?.should be_false
@user.city.should be_nil
@ -90,7 +93,7 @@ describe UserManager do
MaxMindManager.active_record_transaction do |manager|
manager.create_phony_database()
end
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "bob@jamkazam.com", "foobar", "foobar", true, nil, @instruments, Date.new(2001, 1, 1), nil, true, nil, nil, "http://localhost:3000/confirm" )
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "userman7@jamkazam.com", "foobar", "foobar", true, @instruments, Date.new(2001, 1, 1), nil, true, nil, nil, "http://localhost:3000/confirm" )
@user.errors.any?.should be_false
@user.birth_date.should == Date.new(2001, 1, 1)
@ -98,26 +101,26 @@ describe UserManager do
it "duplicate signup failure" do
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "bob@jamkazam.com", "foobar", "foobar", true, nil, @instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm")
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "userman8@jamkazam.com", "foobar", "foobar", true, @instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm")
UserMailer.deliveries.length.should == 1
@user.errors.any?.should be_false
# exactly the same parameters; should dup on email, and send no email
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "bob@jamkazam.com", "foobar", "foobar", true, nil, @instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm")
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "userman8@jamkazam.com", "foobar", "foobar", true, @instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm")
UserMailer.deliveries.length.should == 1
@user.errors.any?.should be_true
@user.errors[:email][0].should == "has already been taken"
end
it "fail on no username" do
@user = @user_manager.signup("127.0.0.1", "", "", "bob@jamkazam.com", "foobar", "foobar", true, nil, @instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm")
@user = @user_manager.signup("127.0.0.1", "", "", "userman10@jamkazam.com", "foobar", "foobar", true, @instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm")
UserMailer.deliveries.length.should == 0
@user.errors.any?.should be_true
@user.errors[:first_name][0].should == "can't be blank"
end
it "fail on no email" do
@user = @user_manager.signup("127.0.0.1", "murp", "blurp", "", "foobar", "foobar", true, nil, @instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm" )
@user = @user_manager.signup("127.0.0.1", "murp", "blurp", "", "foobar", "foobar", true, @instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm" )
UserMailer.deliveries.length.should == 0
@user.errors.any?.should be_true
@user.errors[:email][0].should == "can't be blank"
@ -127,7 +130,7 @@ describe UserManager do
describe "signup_confirm" do
it "fail on no username" do
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "bob@jamkazam.com", "foobar", "foobar", true, nil, @instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm" )
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "userman11@jamkazam.com", "foobar", "foobar", true, @instruments, nil, nil, true, nil, nil, "http://localhost:3000/confirm" )
@user = @user_manager.signup_confirm(@user.signup_token)
@user.email_confirmed.should be_true
end
@ -153,7 +156,7 @@ describe UserManager do
@invitation.accepted.should be_false
@user = @user_manager.signup("127.0.0.1", "bob", "smith", @invitation.email, "foobar", "foobar", true, nil,
@user = @user_manager.signup("127.0.0.1", "bob", "smith", @invitation.email, "foobar", "foobar", true,
@instruments, nil, nil, true, nil, @invitation, "http://localhost:3000/confirm")
@user.errors.any?.should be_false
@ -173,7 +176,7 @@ describe UserManager do
UserMailer.deliveries.clear
@user = @user_manager.signup("127.0.0.1", "bob", "smith", @invitation.email, "foobar", "foobar", true, nil,
@user = @user_manager.signup("127.0.0.1", "bob", "smith", @invitation.email, "foobar", "foobar", true,
@instruments, nil, nil, true, nil, @invitation, "http://localhost:3000/confirm")
@user.errors.any?.should be_false
@ -193,7 +196,7 @@ describe UserManager do
UserMailer.deliveries.clear
@user = @user_manager.signup("127.0.0.1", "bob", "smith", @invitation.email, "foobar", "foobar", true, nil,
@user = @user_manager.signup("127.0.0.1", "bob", "smith", @invitation.email, "foobar", "foobar", true,
@instruments, nil, nil, true, nil, @invitation, "http://localhost:3000/confirm")
@user.errors.any?.should be_false
@ -215,7 +218,7 @@ describe UserManager do
UserMailer.deliveries.clear
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "bob@jamkazam.com", "foobar", "foobar", true, nil,
@user = @user_manager.signup("127.0.0.1", "bob", "smith", "userman12@jamkazam.com", "foobar", "foobar", true,
@instruments, nil, nil, true, nil, @invitation, "http://localhost:3000/confirm")
@user.errors.any?.should be_false

View File

@ -6,6 +6,10 @@ describe "Artifact API ", :type => :api do
subject { page }
before(:each) do
ArtifactUpdate.delete_all
end
describe "versioncheck" do
before do
@artifact = FactoryGirl.create(:artifact_update)
@ -44,12 +48,12 @@ describe "Artifact API ", :type => :api do
end
it { @response.length.should == 2 }
it { @response[@mac_client.product]["size"].should == @mac_client.size }
it { @response[@mac_client.product]["uri"].should_not be_nil }
it { @response["JamClient/Win32"]["size"].should == @win_client.size }
it { @response["JamClient/Win32"]["uri"].should_not be_nil }
it {
@response.length.should == 2
@response[@mac_client.product]["size"].should == @mac_client.size
@response[@mac_client.product]["uri"].should_not be_nil
@response["JamClient/Win32"]["size"].should == @win_client.size
@response["JamClient/Win32"]["uri"].should_not be_nil
}
end
end

View File

@ -6,6 +6,10 @@ describe "Music Session API ", :type => :api do
subject { page }
before(:each) do
MusicSession.delete_all
end
def login(user)
post '/sessions', "session[email]" => user.email, "session[password]" => user.password
rack_mock_session.cookie_jar["remember_token"].should == user.remember_token
@ -424,7 +428,7 @@ describe "Music Session API ", :type => :api do
end
it "join_requests don't show up in session listing" do
client = FactoryGirl.create(:connection, :user => user, :ip_address => "1.1.1.1", :client_id => "1")
client = FactoryGirl.create(:connection, :user => user, :ip_address => "1.1.1.1")
post '/api/sessions.json', defopts.merge({:client_id => client.client_id}).to_json, "CONTENT_TYPE" => 'application/json'
last_response.status.should eql(201)
@ -474,7 +478,7 @@ describe "Music Session API ", :type => :api do
end
it "should now allow join of approval_required=true session" do
client = FactoryGirl.create(:connection, :user => user, :ip_address => "1.1.1.1", :client_id => "1")
client = FactoryGirl.create(:connection, :user => user, :ip_address => "1.1.1.1")
post '/api/sessions.json', defopts.merge({:client_id => client.client_id, :approval_required => true}).to_json, "CONTENT_TYPE" => 'application/json'
last_response.status.should eql(201)

View File

@ -939,7 +939,7 @@ describe "User API", :type => :api do
describe "finalize update email" do
it "success" do
begin_update_email(user, "not_taken_test@jamkazam.com", user.password)
begin_update_email(user, "not_taken_test2@jamkazam.com", user.password)
logout
user.reload
last_response = finalize_update_email(user.update_email_token)

View File

@ -75,6 +75,7 @@ Spork.prefork do
# config.mock_with :flexmock
# config.mock_with :rr
config.mock_with :rspec
config.color_enabled = true
# by default, do not run tests marked as 'slow'
config.filter_run_excluding slow: true unless ENV['RUN_SLOW_TESTS'] == "1"
@ -93,12 +94,9 @@ Spork.prefork do
config.infer_base_class_for_anonymous_controllers = false
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation, {:except => %w[instruments genres] })
end
config.before(:each) do
# DatabaseCleaner.strategy = :transaction
DatabaseCleaner.strategy = :truncation, {:except => %w[instruments genres] }
if example.metadata[:js]
page.driver.resize(1920, 1080)
@ -107,18 +105,15 @@ Spork.prefork do
end
config.before(:each, :js => true) do
DatabaseCleaner.strategy = :truncation, {:except => %w[instruments genres] }
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
if example.metadata[:js]
sleep 0.2 # ugh. necessary though otherwise intermittent failures: http://stackoverflow.com/questions/14265983/upgrading-capybara-from-1-0-1-to-1-1-4-makes-database-cleaner-break-my-specs
#sleep (ENV['SLEEP_JS'] || 0.2).to_i # necessary though otherwise intermittent failures: http://stackoverflow.com/questions/14265983/upgrading-capybara-from-1-0-1-to-1-1-4-makes-database-cleaner-break-my-specs
end
DatabaseCleaner.clean
end
end
end

View File

@ -34,3 +34,40 @@ def sign_in_poltergeist(user)
page.driver.browser.manage.add_cookie :name => :remember_token, :value => user.remember_token
end
end
def sign_out()
if Capybara.javascript_driver == :poltergeist
page.driver.remove_cookie(:remember_token)
else
page.driver.browser.manage.remove_cookie :name => :remember_token
end
end
def wait_for_ajax(wait=Capybara.default_wait_time)
wait = wait * 10 #(because we sleep .1)
counter = 0
while page.execute_script("$.active").to_i > 0
counter += 1
sleep(0.1)
raise "AJAX request took longer than #{wait} seconds." if counter >= wait
end
end
# waits until the user object has been requested, which comes after the 'curtain' is lifted
# and after a call to /api/user/:id for the current user is called initially
def wait_until_user(wait=Capybara.default_wait_time)
wait = wait * 10 #(because we sleep .1)
counter = 0
# while page.execute_script("$('.curtain').is(:visible)") == "true"
# counter += 1
# sleep(0.1)
# raise "Waiting for user to populate took longer than #{wait} seconds." if counter >= wait
# end
end
def wait_until_curtain_gone
should have_no_selector('.curtain')
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,462 @@
/*!
* iCheck v0.9.1, http://git.io/uhUPMA
* =================================
* Powerful jQuery plugin for checkboxes and radio buttons customization
*
* (c) 2013 Damir Foy, http://damirfoy.com
* MIT Licensed
*/
(function($) {
// Cached vars
var _iCheck = 'iCheck',
_iCheckHelper = _iCheck + '-helper',
_checkbox = 'checkbox',
_radio = 'radio',
_checked = 'checked',
_unchecked = 'un' + _checked,
_disabled = 'disabled',
_determinate = 'determinate',
_indeterminate = 'in' + _determinate,
_update = 'update',
_type = 'type',
_click = 'click',
_touch = 'touchbegin.i touchend.i',
_add = 'addClass',
_remove = 'removeClass',
_callback = 'trigger',
_label = 'label',
_cursor = 'cursor',
_mobile = /ipad|iphone|ipod|android|blackberry|windows phone|opera mini|silk/i.test(navigator.userAgent);
// Plugin init
$.fn[_iCheck] = function(options, fire) {
// Walker
var handle = ':' + _checkbox + ', :' + _radio,
stack = $(),
walker = function(object) {
object.each(function() {
var self = $(this);
if (self.is(handle)) {
stack = stack.add(self);
} else {
stack = stack.add(self.find(handle));
};
});
};
// Check if we should operate with some method
if (/^(check|uncheck|toggle|indeterminate|determinate|disable|enable|update|destroy)$/i.test(options)) {
// Normalize method's name
options = options.toLowerCase();
// Find checkboxes and radio buttons
walker(this);
return stack.each(function() {
if (options == 'destroy') {
tidy(this, 'ifDestroyed');
} else {
operate($(this), true, options);
};
// Fire method's callback
if ($.isFunction(fire)) {
fire();
};
});
// Customization
} else if (typeof options == 'object' || !options) {
// Check if any options were passed
var settings = $.extend({
checkedClass: _checked,
disabledClass: _disabled,
indeterminateClass: _indeterminate,
labelHover: true
}, options),
selector = settings.handle,
hoverClass = settings.hoverClass || 'hover',
focusClass = settings.focusClass || 'focus',
activeClass = settings.activeClass || 'active',
labelHover = !!settings.labelHover,
labelHoverClass = settings.labelHoverClass || 'hover',
// Setup clickable area
area = ('' + settings.increaseArea).replace('%', '') | 0;
// Selector limit
if (selector == _checkbox || selector == _radio) {
handle = ':' + selector;
};
// Clickable area limit
if (area < -50) {
area = -50;
};
// Walk around the selector
walker(this);
return stack.each(function() {
// If already customized
tidy(this);
var self = $(this),
node = this,
id = node.id,
// Layer styles
offset = -area + '%',
size = 100 + (area * 2) + '%',
layer = {
position: 'absolute',
top: offset,
left: offset,
display: 'block',
width: size,
height: size,
margin: 0,
padding: 0,
background: '#fff',
border: 0,
opacity: 0
},
// Choose how to hide input
hide = _mobile ? {
position: 'absolute',
visibility: 'hidden'
} : area ? layer : {
position: 'absolute',
opacity: 0
},
// Get proper class
className = node[_type] == _checkbox ? settings.checkboxClass || 'i' + _checkbox : settings.radioClass || 'i' + _radio,
// Find assigned labels
label = $(_label + '[for="' + id + '"]').add(self.closest(_label)),
// Wrap input
parent = self.wrap('<div class="' + className + '"/>')[_callback]('ifCreated').parent().append(settings.insert),
// Layer addition
helper = $('<ins class="' + _iCheckHelper + '"/>').css(layer).appendTo(parent);
// Finalize customization
self.data(_iCheck, {o: settings, s: self.attr('style')}).css(hide);
!!settings.inheritClass && parent[_add](node.className);
!!settings.inheritID && id && parent.attr('id', _iCheck + '-' + id);
parent.css('position') == 'static' && parent.css('position', 'relative');
operate(self, true, _update);
// Label events
if (label.length) {
label.on(_click + '.i mouseenter.i mouseleave.i ' + _touch, function(event) {
var type = event[_type],
item = $(this);
// Do nothing if input is disabled
if (!node[_disabled]) {
// Click
if (type == _click) {
operate(self, false, true);
// Hover state
} else if (labelHover) {
// mouseleave|touchend
if (/ve|nd/.test(type)) {
parent[_remove](hoverClass);
item[_remove](labelHoverClass);
} else {
parent[_add](hoverClass);
item[_add](labelHoverClass);
};
};
if (_mobile) {
event.stopPropagation();
} else {
return false;
};
};
});
};
// Input events
self.on(_click + '.i focus.i blur.i keyup.i keydown.i keypress.i', function(event) {
var type = event[_type],
key = event.keyCode;
// Click
if (type == _click) {
return false;
// Keydown
} else if (type == 'keydown' && key == 32) {
if (!(node[_type] == _radio && node[_checked])) {
if (node[_checked]) {
off(self, _checked);
} else {
on(self, _checked);
};
};
return false;
// Keyup
} else if (type == 'keyup' && node[_type] == _radio) {
!node[_checked] && on(self, _checked);
// Focus/blur
} else if (/us|ur/.test(type)) {
parent[type == 'blur' ? _remove : _add](focusClass);
};
});
// Helper events
helper.on(_click + ' mousedown mouseup mouseover mouseout ' + _touch, function(event) {
var type = event[_type],
// mousedown|mouseup
toggle = /wn|up/.test(type) ? activeClass : hoverClass;
// Do nothing if input is disabled
if (!node[_disabled]) {
// Click
if (type == _click) {
operate(self, false, true);
// Active and hover states
} else {
// State is on
if (/wn|er|in/.test(type)) {
// mousedown|mouseover|touchbegin
parent[_add](toggle);
// State is off
} else {
parent[_remove](toggle + ' ' + activeClass);
};
// Label hover
if (label.length && labelHover && toggle == hoverClass) {
// mouseout|touchend
label[/ut|nd/.test(type) ? _remove : _add](labelHoverClass);
};
};
if (_mobile) {
event.stopPropagation();
} else {
return false;
};
};
});
});
} else {
return this;
};
};
// Do something with inputs
function operate(input, direct, method) {
var node = input[0];
state = /er/.test(method) ? _indeterminate : /bl/.test(method) ? _disabled : _checked,
active = method == _update ? {
checked: node[_checked],
disabled: node[_disabled],
indeterminate: input.attr(_indeterminate) == 'true' || input.attr(_determinate) == 'false'
} : node[state];
// Check, disable or indeterminate
if (/^(ch|di|in)/.test(method) && !active) {
on(input, state);
// Uncheck, enable or determinate
} else if (/^(un|en|de)/.test(method) && active) {
off(input, state);
// Update
} else if (method == _update) {
// Handle states
for (var state in active) {
if (active[state]) {
on(input, state, true);
} else {
off(input, state, true);
};
};
} else if (!direct || method == 'toggle') {
// Helper or label was clicked
if (!direct) {
input[_callback]('ifClicked');
};
// Toggle checked state
if (active) {
if (node[_type] !== _radio) {
off(input, state);
};
} else {
on(input, state);
};
};
};
// Add checked, disabled or indeterminate state
function on(input, state, keep) {
var node = input[0],
parent = input.parent(),
checked = state == _checked,
indeterminate = state == _indeterminate,
callback = indeterminate ? _determinate : checked ? _unchecked : 'enabled',
regular = option(node, callback + capitalize(node[_type])),
specific = option(node, state + capitalize(node[_type]));
// Prevent unnecessary actions
if (node[state] !== true) {
// Toggle assigned radio buttons
if (!keep && state == _checked && node[_type] == _radio && node.name) {
var form = input.closest('form'),
inputs = 'input[name="' + node.name + '"]';
inputs = form.length ? form.find(inputs) : $(inputs);
inputs.each(function() {
if (this !== node && $.data(this, _iCheck)) {
off($(this), state);
};
});
};
// Indeterminate state
if (indeterminate) {
// Add indeterminate state
node[state] = true;
// Remove checked state
if (node[_checked]) {
off(input, _checked, 'force');
};
// Checked or disabled state
} else {
// Add checked or disabled state
if (!keep) {
node[state] = true;
};
// Remove indeterminate state
if (checked && node[_indeterminate]) {
off(input, _indeterminate, false);
};
};
// Trigger callbacks
callbacks(input, checked, state, keep);
};
// Add proper cursor
if (node[_disabled] && !!option(node, _cursor, true)) {
parent.find('.' + _iCheckHelper).css(_cursor, 'default');
};
// Add state class
parent[_add](specific || option(node, state));
// Remove regular state class
parent[_remove](regular || option(node, callback) || '');
};
// Remove checked, disabled or indeterminate state
function off(input, state, keep) {
var node = input[0],
parent = input.parent(),
checked = state == _checked,
indeterminate = state == _indeterminate,
callback = indeterminate ? _determinate : checked ? _unchecked : 'enabled',
regular = option(node, callback + capitalize(node[_type])),
specific = option(node, state + capitalize(node[_type]));
// Prevent unnecessary actions
if (node[state] !== false) {
// Toggle state
if (indeterminate || !keep || keep == 'force') {
node[state] = false;
};
// Trigger callbacks
callbacks(input, checked, callback, keep);
};
// Add proper cursor
if (!node[_disabled] && !!option(node, _cursor, true)) {
parent.find('.' + _iCheckHelper).css(_cursor, 'pointer');
};
// Remove state class
parent[_remove](specific || option(node, state) || '');
// Add regular state class
parent[_add](regular || option(node, callback));
};
// Remove all traces
function tidy(node, callback) {
if ($.data(node, _iCheck)) {
var input = $(node);
// Remove everything except input
input.parent().html(input.attr('style', $.data(node, _iCheck).s || '')[_callback](callback || ''));
// Unbind events
input.off('.i').unwrap();
$(_label + '[for="' + node.id + '"]').add(input.closest(_label)).off('.i');
};
};
// Get some option
function option(node, state, regular) {
if ($.data(node, _iCheck)) {
return $.data(node, _iCheck).o[state + (regular ? '' : 'Class')];
};
};
// Capitalize some string
function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
};
// Executable handlers
function callbacks(input, checked, callback, keep) {
if (!keep) {
if (checked) {
input[_callback]('ifToggled');
};
input[_callback]('ifChanged')[_callback]('if' + capitalize(callback));
};
};
})(jQuery);

View File

@ -0,0 +1,60 @@
/* iCheck plugin Minimal skin, black
----------------------------------- */
.icheckbox_minimal,
.iradio_minimal {
display: block;
margin: 0;
padding: 0;
width: 18px;
height: 18px;
background: url(/assets/icheck/jamkazam.png) no-repeat;
border: none;
cursor: pointer;
}
.icheckbox_minimal {
background-position: 0 0;
}
.icheckbox_minimal.hover {
background-position: -20px 0;
}
.icheckbox_minimal.checked {
background-position: -40px 0;
}
.icheckbox_minimal.disabled {
background-position: -60px 0;
cursor: default;
}
.icheckbox_minimal.checked.disabled {
background-position: -80px 0;
}
.iradio_minimal {
background-position: -100px 0;
}
.iradio_minimal.hover {
background-position: -120px 0;
}
.iradio_minimal.checked {
background-position: -140px 0;
}
.iradio_minimal.disabled {
background-position: -160px 0;
cursor: default;
}
.iradio_minimal.checked.disabled {
background-position: -180px 0;
}
/* Retina support */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (-moz-min-device-pixel-ratio: 1.5),
only screen and (-o-min-device-pixel-ratio: 3/2),
only screen and (min-device-pixel-ratio: 1.5) {
.icheckbox_minimal,
.iradio_minimal {
background-image: url(/assets/icheck/jamkazam@2x.png);
-webkit-background-size: 200px 20px;
background-size: 200px 20px;
}
}

View File

@ -15,7 +15,7 @@
/* Selection Border */
.jcrop-vline,
.jcrop-hline {
background: #ffffff url("Jcrop.gif");
background: #ffffff url("/assets/Jcrop.gif");
font-size: 0;
position: absolute;
}

View File

@ -538,11 +538,13 @@ module JamWebsockets
unless context = @clients[client]
@log.warn "*** WARNING: unable to find context due to heartbeat from client: #{client.client_id}; calling cleanup"
cleanup_client(client)
raise SessionError, 'context state is gone. please reconnect.'
else
connection = Connection.find_by_user_id_and_client_id(context.user.id, context.client.client_id)
if connection.nil?
@log.warn "*** WARNING: unable to find connection due to heartbeat from client: #{context}; calling cleanup_client"
cleanup_client(client)
raise SessionError, 'connection state is gone. please reconnect.'
else
connection.touch

View File

@ -43,6 +43,10 @@ module JamWebsockets
end
end
def stop
EventMachine::stop_event_loop
end
def start_websocket_listener(listen_ip, port, emwebsocket_debug)
EventMachine::WebSocket.start(:host => listen_ip, :port => port, :debug => emwebsocket_debug) do |ws|
@log.info "new client #{ws}"