VRFS-1483 merge
This commit is contained in:
commit
3204de01e6
|
|
@ -136,5 +136,5 @@ events.sql
|
|||
cascading_delete_constraints_for_release.sql
|
||||
events_social_description.sql
|
||||
fix_broken_cities.sql
|
||||
notifications_with_text.sql
|
||||
emails.sql
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE notifications ADD COLUMN message TEXT;
|
||||
|
|
@ -49,6 +49,9 @@ message ClientMessage {
|
|||
BAND_INVITATION = 225;
|
||||
BAND_INVITATION_ACCEPTED = 230;
|
||||
BAND_SESSION_JOIN = 235;
|
||||
|
||||
// text message
|
||||
TEXT_MESSAGE = 236;
|
||||
|
||||
MUSICIAN_SESSION_FRESH = 240;
|
||||
MUSICIAN_SESSION_STALE = 245;
|
||||
|
|
@ -125,6 +128,9 @@ message ClientMessage {
|
|||
optional BandInvitationAccepted band_invitation_accepted = 230;
|
||||
optional BandSessionJoin band_session_join = 235;
|
||||
|
||||
// text message
|
||||
optional TextMessage text_message = 236;
|
||||
|
||||
optional MusicianSessionFresh musician_session_fresh = 240;
|
||||
optional MusicianSessionStale musician_session_stale = 245;
|
||||
|
||||
|
|
@ -381,6 +387,16 @@ message BandSessionJoin {
|
|||
optional string created_at = 8;
|
||||
}
|
||||
|
||||
message TextMessage {
|
||||
optional string photo_url = 1;
|
||||
optional string sender_name = 2;
|
||||
optional string sender_id = 3;
|
||||
optional string msg = 4;
|
||||
optional string notification_id = 5;
|
||||
optional string created_at = 6;
|
||||
optional bool clipped_msg = 7;
|
||||
}
|
||||
|
||||
// route_to: client:
|
||||
// sent by server to let the rest of the participants know a client has become active again after going stale
|
||||
message MusicianSessionFresh {
|
||||
|
|
|
|||
|
|
@ -233,6 +233,24 @@
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
def text_message(email, sender_id, sender_name, sender_photo_url, message)
|
||||
subject = "Message from #{sender_name}"
|
||||
unique_args = {:type => "text_message"}
|
||||
|
||||
@note = message
|
||||
@root_url = APP_CONFIG.external_root_url
|
||||
@sender_id = sender_id
|
||||
@sender_name = sender_name
|
||||
@sender_photo_url = sender_photo_url
|
||||
sendgrid_category "Notification"
|
||||
sendgrid_unique_args :type => unique_args[:type]
|
||||
mail(:to => email, :subject => subject) do |format|
|
||||
format.text
|
||||
format.html { render :layout => "from_user_mailer" }
|
||||
end
|
||||
end
|
||||
|
||||
# def send_notification(email, subject, msg, unique_args)
|
||||
# @body = msg
|
||||
# sendgrid_category "Notification"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
<% provide(:title, "Message from #{@sender_name}") %>
|
||||
<% provide(:photo_url, @sender_photo_url) %>
|
||||
|
||||
<% content_for :note do %>
|
||||
<%= @note %>
|
||||
|
||||
<p>To reply to this message, <a href="<%= @root_url %>/client#/home/text-message/d1=<%= @sender_id %>">click here</a>.</p>
|
||||
<% end %>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<%= @sender_name %> says: <%= @note %>
|
||||
|
||||
To reply to this message, click here: <%= @root_url %>/client#/home/text-message/d1=<%= @sender_id %>
|
||||
|
|
@ -30,4 +30,7 @@ module NotificationTypes
|
|||
BAND_INVITATION_ACCEPTED = "BAND_INVITATION_ACCEPTED"
|
||||
BAND_SESSION_JOIN = "BAND_SESSION_JOIN" # cleared using SESSION_ENDED notification
|
||||
|
||||
# general purpose text message
|
||||
TEXT_MESSAGE = "TEXT_MESSAGE"
|
||||
|
||||
end
|
||||
|
|
@ -75,6 +75,8 @@ module ValidationMessages
|
|||
MUST_BE_A_MUSICIAN = "must be a musician"
|
||||
CLAIMED_RECORDING_ALREADY_IN_PROGRESS = "already started by someone else"
|
||||
|
||||
# notification
|
||||
DIFFERENT_SOURCE_TARGET = 'can\'t be same as the sender'
|
||||
|
||||
# takes either a string/string hash, or a string/array-of-strings|symbols hash,
|
||||
# and creates a ActiveRecord.errors style object
|
||||
|
|
|
|||
|
|
@ -1,7 +1,14 @@
|
|||
module JamRuby
|
||||
# if a bad argument is supplied.
|
||||
# Why not use the default ruby argument error? Using this one allows us to know our API layer threw this, versus us using some core library incorrectly
|
||||
# So why not use the default ruby argument error? Using this one allows us to know our API layer threw this, versus us using some core library incorrectly
|
||||
class JamArgumentError < ArgumentError
|
||||
|
||||
attr_accessor :field, :field_message
|
||||
|
||||
def initialize(message, field = nil)
|
||||
@message = message
|
||||
@field_message = message
|
||||
@field = field
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -33,7 +33,7 @@ end
|
|||
class NoProfanityValidator < ActiveModel::EachValidator
|
||||
# implement the method called during validation
|
||||
def validate_each(record, attribute, value)
|
||||
record.errors[attribute] << 'Cannot contain profanity' if Profanity.is_profane?(value)
|
||||
record.errors[attribute] << 'cannot contain profanity' if Profanity.is_profane?(value)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -561,6 +561,25 @@ module JamRuby
|
|||
)
|
||||
end
|
||||
|
||||
# creates the general purpose text message
|
||||
def text_message(receiver_id, sender_photo_url, sender_name, sender_id, msg, clipped_msg, notification_id, created_at)
|
||||
text_message = Jampb::TextMessage.new(
|
||||
:photo_url => sender_photo_url,
|
||||
:sender_name => sender_name,
|
||||
:sender_id => sender_id,
|
||||
:msg => msg,
|
||||
:clipped_msg => clipped_msg,
|
||||
:notification_id => notification_id,
|
||||
:created_at => created_at
|
||||
)
|
||||
|
||||
Jampb::ClientMessage.new(
|
||||
:type => ClientMessage::Type::TEXT_MESSAGE,
|
||||
:route_to => USER_TARGET_PREFIX + receiver_id,
|
||||
:text_message => text_message
|
||||
)
|
||||
end
|
||||
|
||||
# create a musician fresh session message
|
||||
def musician_session_fresh(session_id, user_id, username, photo_url)
|
||||
fresh = Jampb::MusicianSessionFresh.new(
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ module JamRuby
|
|||
# ensure recipient is a Musician
|
||||
user = User.find(user_id)
|
||||
unless user.musician?
|
||||
raise JamRuby::JamArgumentError, BAND_INVITATION_FAN_RECIPIENT_ERROR
|
||||
raise JamRuby::JamArgumentError.new(BAND_INVITATION_FAN_RECIPIENT_ERROR, :receiver)
|
||||
end
|
||||
|
||||
band_invitation.band_id = band_id
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ module JamRuby
|
|||
validates :email, format: {with: VALID_EMAIL_REGEX}, :if => lambda { |iu| iu.email_required? }
|
||||
validates :autofriend, :inclusion => {:in => [nil, true, false]}
|
||||
validates :invitation_code, :presence => true
|
||||
validates :note, length: {maximum: 400}, no_profanity: true # 400 == arbitrary.
|
||||
validates :note, length: {maximum: 1000}, no_profanity: true # 1000 == arbitrary.
|
||||
|
||||
validate :one_facebook_invite_per_user, :if => lambda { |iu| iu.facebook_invite? }
|
||||
validate :valid_personalized_invitation
|
||||
|
|
|
|||
|
|
@ -14,6 +14,14 @@ module JamRuby
|
|||
belongs_to :recording, :class_name => "JamRuby::Recording", :foreign_key => "recording_id"
|
||||
|
||||
validates :target_user, :presence => true
|
||||
validates :message, length: {minimum: 1, maximum: 400}, no_profanity: true, if: :text_message?
|
||||
validate :different_source_target, if: :text_message?
|
||||
|
||||
def different_source_target
|
||||
unless target_user_id.nil? || source_user_id.nil?
|
||||
errors.add(:target_user, ValidationMessages::DIFFERENT_SOURCE_TARGET) if target_user_id == source_user_id
|
||||
end
|
||||
end
|
||||
|
||||
def index(user_id)
|
||||
Notification.where(:target_user_id => user_id).limit(50)
|
||||
|
|
@ -42,7 +50,7 @@ module JamRuby
|
|||
band = Band.find(self.band_id)
|
||||
end
|
||||
|
||||
return self.class.format_msg(self.description, source_user, band)
|
||||
self.class.format_msg(self.description, source_user, band)
|
||||
end
|
||||
|
||||
# TODO: MAKE ALL METHODS BELOW ASYNC SO THE CLIENT DOESN'T BLOCK ON NOTIFICATION LOGIC
|
||||
|
|
@ -719,6 +727,38 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def send_text_message(message, sender, receiver)
|
||||
|
||||
notification = Notification.new
|
||||
notification.description = NotificationTypes::TEXT_MESSAGE
|
||||
notification.message = message
|
||||
notification.source_user_id = sender.id
|
||||
notification.target_user_id = receiver.id if receiver
|
||||
if notification.save
|
||||
if receiver.online
|
||||
clip_at = 200
|
||||
msg_is_clipped = message.length > clip_at
|
||||
truncated_msg = message[0..clip_at - 1]
|
||||
msg = @@message_factory.text_message(
|
||||
receiver.id,
|
||||
sender.photo_url,
|
||||
sender.name,
|
||||
sender.id,
|
||||
truncated_msg,
|
||||
msg_is_clipped,
|
||||
notification.id,
|
||||
notification.created_date)
|
||||
|
||||
@@mq_router.publish_to_user(receiver.id, msg)
|
||||
|
||||
else
|
||||
UserMailer.text_message(receiver.email, sender.id, sender.name, sender.resolved_photo_url, message).deliver
|
||||
end
|
||||
end
|
||||
|
||||
notification
|
||||
end
|
||||
|
||||
def send_band_invitation(band, band_invitation, sender, receiver)
|
||||
|
||||
notification = Notification.new
|
||||
|
|
@ -830,5 +870,11 @@ module JamRuby
|
|||
@@mq_router.server_publish_to_everyone_in_session(music_session, msg)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def text_message?
|
||||
description == 'TEXT_MESSAGE'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -780,7 +780,7 @@ module JamRuby
|
|||
# if you came in from an invite and used the same email to signup,
|
||||
# then we know you are a real human and that your email is valid.
|
||||
# lucky! we'll log you in immediately
|
||||
if invited_user.email.casecmp(user.email).zero?
|
||||
if invited_user.email && invited_user.email.casecmp(user.email).zero?
|
||||
user.email_confirmed = true
|
||||
user.signup_token = nil
|
||||
else
|
||||
|
|
|
|||
|
|
@ -431,4 +431,11 @@ FactoryGirl.define do
|
|||
test_emails 4.times.collect { Faker::Internet.safe_email }.join(',')
|
||||
end
|
||||
|
||||
factory :notification, :class => JamRuby::Notification do
|
||||
|
||||
factory :notification_text_message do
|
||||
description 'TEXT_MESSAGE'
|
||||
message Faker::Lorem.characters(10)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,137 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Notification do
|
||||
|
||||
before(:each) do
|
||||
UserMailer.deliveries.clear
|
||||
|
||||
end
|
||||
|
||||
describe "send_text_message" do
|
||||
it "success when offline" do
|
||||
receiver = FactoryGirl.create(:user)
|
||||
sender = FactoryGirl.create(:user)
|
||||
message = "Just a test message!"
|
||||
|
||||
called_count = 0
|
||||
MQRouter.any_instance.stub(:publish_to_user) do |receiver_id, msg|
|
||||
called_count += 1
|
||||
end
|
||||
|
||||
notification = Notification.send_text_message(message, sender, receiver)
|
||||
|
||||
notification.errors.any?.should be_false
|
||||
UserMailer.deliveries.length.should == 1
|
||||
called_count.should == 0
|
||||
end
|
||||
|
||||
|
||||
it "success when online" do
|
||||
receiver = FactoryGirl.create(:user)
|
||||
receiver_connection = FactoryGirl.create(:connection, user: receiver)
|
||||
sender = FactoryGirl.create(:user)
|
||||
|
||||
message = "Just a test message!"
|
||||
|
||||
called_count = 0
|
||||
saved_msg = nil
|
||||
MQRouter.any_instance.stub(:publish_to_user) do |receiver_id, msg|
|
||||
saved_msg = msg
|
||||
called_count += 1
|
||||
end
|
||||
|
||||
notification = Notification.send_text_message(message, sender, receiver)
|
||||
|
||||
notification.errors.any?.should be_false
|
||||
UserMailer.deliveries.length.should == 0
|
||||
called_count.should == 1
|
||||
saved_msg.text_message.msg.should == message
|
||||
saved_msg.text_message.photo_url.should == ''
|
||||
saved_msg.text_message.sender_name.should == sender.name
|
||||
saved_msg.text_message.notification_id.should == notification.id
|
||||
saved_msg.text_message.created_at = notification.created_date
|
||||
saved_msg.text_message.clipped_msg.should be_false
|
||||
end
|
||||
|
||||
it "success when online with long message" do
|
||||
receiver = FactoryGirl.create(:user)
|
||||
receiver_connection = FactoryGirl.create(:connection, user: receiver)
|
||||
sender = FactoryGirl.create(:user)
|
||||
|
||||
message = "0" * 203 # 200 is clip size
|
||||
|
||||
called_count = 0
|
||||
saved_msg = nil
|
||||
MQRouter.any_instance.stub(:publish_to_user) do |receiver_id, msg|
|
||||
saved_msg = msg
|
||||
called_count += 1
|
||||
end
|
||||
|
||||
notification = Notification.send_text_message(message, sender, receiver)
|
||||
|
||||
notification.errors.any?.should be_false
|
||||
UserMailer.deliveries.length.should == 0
|
||||
called_count.should == 1
|
||||
saved_msg.text_message.msg.should == "0" * 200
|
||||
saved_msg.text_message.photo_url.should == ''
|
||||
saved_msg.text_message.sender_name.should == sender.name
|
||||
saved_msg.text_message.notification_id.should == notification.id
|
||||
saved_msg.text_message.created_at = notification.created_date
|
||||
saved_msg.text_message.clipped_msg.should be_true
|
||||
end
|
||||
|
||||
it "fails with profanity" do
|
||||
receiver = FactoryGirl.create(:user)
|
||||
sender = FactoryGirl.create(:user)
|
||||
message = "ass"
|
||||
|
||||
called_count = 0
|
||||
MQRouter.any_instance.stub(:publish_to_user) do |receiver_id, msg|
|
||||
called_count += 1
|
||||
end
|
||||
|
||||
notification = Notification.send_text_message(message, sender, receiver)
|
||||
|
||||
notification.errors.any?.should be_true
|
||||
notification.errors[:message].should == ['cannot contain profanity']
|
||||
UserMailer.deliveries.length.should == 0
|
||||
called_count.should == 0
|
||||
end
|
||||
|
||||
it "fails when target is same as receiver" do
|
||||
receiver = FactoryGirl.create(:user)
|
||||
sender = FactoryGirl.create(:user)
|
||||
message = "yo"
|
||||
|
||||
called_count = 0
|
||||
MQRouter.any_instance.stub(:publish_to_user) do |receiver_id, msg|
|
||||
called_count += 1
|
||||
end
|
||||
|
||||
notification = Notification.send_text_message(message, sender, sender)
|
||||
|
||||
notification.errors.any?.should be_true
|
||||
notification.errors[:target_user].should == [ValidationMessages::DIFFERENT_SOURCE_TARGET]
|
||||
UserMailer.deliveries.length.should == 0
|
||||
called_count.should == 0
|
||||
end
|
||||
|
||||
it "fails when there is no message" do
|
||||
receiver = FactoryGirl.create(:user)
|
||||
sender = FactoryGirl.create(:user)
|
||||
message = ''
|
||||
|
||||
called_count = 0
|
||||
MQRouter.any_instance.stub(:publish_to_user) do |receiver_id, msg|
|
||||
called_count += 1
|
||||
end
|
||||
|
||||
notification = Notification.send_text_message(message, sender, receiver)
|
||||
|
||||
notification.errors.any?.should be_true
|
||||
notification.errors[:message].should == ['is too short (minimum is 1 characters)']
|
||||
UserMailer.deliveries.length.should == 0
|
||||
called_count.should == 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -31,6 +31,12 @@ describe "RenderMailers", :slow => true do
|
|||
it { @filename="password_changed"; UserMailer.password_changed(user).deliver }
|
||||
it { @filename="updated_email"; UserMailer.updated_email(user).deliver }
|
||||
it { @filename="updating_email"; UserMailer.updating_email(user).deliver }
|
||||
|
||||
describe "has sending user" do
|
||||
let(:user2) { FactoryGirl.create(:user) }
|
||||
it { @filename="text_message"; UserMailer.text_message(user.email, user2.id, user2.name, user2.resolved_photo_url, 'Get online!!').deliver }
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "InvitedUserMailer emails" do
|
||||
|
|
|
|||
|
|
@ -49,6 +49,9 @@
|
|||
BAND_INVITATION : "BAND_INVITATION",
|
||||
BAND_INVITATION_ACCEPTED : "BAND_INVITATION_ACCEPTED",
|
||||
|
||||
// text message
|
||||
TEXT_MESSAGE : "TEXT_MESSAGE",
|
||||
|
||||
// broadcast notifications
|
||||
SOURCE_UP_REQUESTED : "SOURCE_UP_REQUESTED",
|
||||
SOURCE_DOWN_REQUESTED : "SOURCE_DOWN_REQUESTED",
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
}
|
||||
|
||||
function handleDeleteAudioProfile(audioProfileId) {
|
||||
console.log("deleting audio profile: " + audioProfileId);
|
||||
logger.debug("deleting audio profile: " + audioProfileId);
|
||||
|
||||
context.jamClient.TrackDeleteProfile(audioProfileId);
|
||||
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@
|
|||
|
||||
function regionListFailure(jqXHR, textStatus, errorThrown) {
|
||||
if(jqXHR.status == 422) {
|
||||
console.log("no regions found for country: " + recentUserDetail.country);
|
||||
logger.debug("no regions found for country: " + recentUserDetail.country);
|
||||
}
|
||||
else {
|
||||
app.ajaxError(arguments);
|
||||
|
|
@ -264,7 +264,7 @@
|
|||
|
||||
function cityListFailure(jqXHR, textStatus, errorThrown) {
|
||||
if(jqXHR.status == 422) {
|
||||
console.log("no cities found for country/region: " + recentUserDetail.country + "/" + recentUserDetail.state);
|
||||
logger.debug("no cities found for country/region: " + recentUserDetail.country + "/" + recentUserDetail.state);
|
||||
}
|
||||
else {
|
||||
app.ajaxError(arguments);
|
||||
|
|
@ -456,7 +456,7 @@
|
|||
}
|
||||
|
||||
function updateCityList(selectedCountry, selectedRegion, cityElement) {
|
||||
console.log("updating city list: selectedCountry %o, selectedRegion %o", selectedCountry, selectedRegion);
|
||||
logger.debug("updating city list: selectedCountry %o, selectedRegion %o", selectedCountry, selectedRegion);
|
||||
|
||||
// only update cities
|
||||
if (selectedCountry && selectedRegion) {
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@
|
|||
self.updatingAvatar = true;
|
||||
renderAvatarSpinner();
|
||||
|
||||
console.log("Converting...");
|
||||
logger.debug("Converting...");
|
||||
|
||||
// we convert two times; first we crop to the selected region,
|
||||
// then we scale to 88x88 (targetCropSize X targetCropSize), which is the largest size we use throughout the site.
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
//= require jquery.infinitescroll
|
||||
//= require jquery.hoverIntent
|
||||
//= require jquery.dotdotdot
|
||||
//= require AAA_Log
|
||||
//= require globals
|
||||
//= require AAB_message_factory
|
||||
//= require AAC_underscore
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
context.JK.BandSetupScreen = function (app) {
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var friendSelectorDialog = null;
|
||||
var inviteMusiciansUtil = null;
|
||||
var invitationDialog = null;
|
||||
var autoComplete = null;
|
||||
var userNames = [];
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
var nilOptionStr = '<option value=""></option>';
|
||||
var nilOptionText = 'n/a';
|
||||
var bandId = '';
|
||||
var friendInput=null;
|
||||
|
||||
function is_new_record() {
|
||||
return bandId.length == 0;
|
||||
|
|
@ -62,7 +63,7 @@
|
|||
$("#band-setup-step-1").show();
|
||||
$("#band-setup-step-2").hide();
|
||||
|
||||
$('#band-invitee-input')
|
||||
$(friendInput)
|
||||
.unbind('blur')
|
||||
.attr("placeholder", "Looking up friends...")
|
||||
.prop('disabled', true)
|
||||
|
|
@ -156,7 +157,7 @@
|
|||
function createBandInvitations(bandId, onComplete) {
|
||||
var callCount = 0;
|
||||
var totalInvitations = 0;
|
||||
$('#selected-band-invitees .invitation').each(function (index, invitation) {
|
||||
$('#selected-friends-band .invitation').each(function (index, invitation) {
|
||||
callCount++;
|
||||
totalInvitations++;
|
||||
var userId = $(invitation).attr('user-id');
|
||||
|
|
@ -179,16 +180,13 @@
|
|||
}
|
||||
|
||||
function beforeShow(data) {
|
||||
userNames = [];
|
||||
userIds = [];
|
||||
userPhotoUrls = [];
|
||||
inviteMusiciansUtil.clearSelections();
|
||||
bandId = data.id == 'new' ? '' : data.id;
|
||||
resetForm();
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
friendSelectorDialog.setCallback(friendSelectorCallback);
|
||||
loadFriends();
|
||||
inviteMusiciansUtil.loadFriends();
|
||||
|
||||
if (!is_new_record()) {
|
||||
$("#band-setup-title").html("edit band");
|
||||
|
|
@ -240,38 +238,6 @@
|
|||
});
|
||||
}
|
||||
|
||||
// TODO: this is repeated in createSession.js.erb
|
||||
function loadFriends() {
|
||||
rest.getFriends({ id: context.JK.currentUserId })
|
||||
.done(function (friends) {
|
||||
$.each(friends, function () {
|
||||
userNames.push(this.name);
|
||||
userIds.push(this.id);
|
||||
userPhotoUrls.push(this.photo_url);
|
||||
});
|
||||
|
||||
var autoCompleteOptions = {
|
||||
lookup: { suggestions: userNames, data: userIds },
|
||||
onSelect: addInvitation
|
||||
};
|
||||
|
||||
$('#band-invitee-input').attr("placeholder", "Type a friend\'s name").prop('disabled', false);
|
||||
|
||||
if (!autoComplete) {
|
||||
autoComplete = $('#band-invitee-input').autocomplete(autoCompleteOptions);
|
||||
}
|
||||
else {
|
||||
autoComplete.setOptions(autoCompleteOptions);
|
||||
}
|
||||
|
||||
$(".autocomplete").width("150px");
|
||||
})
|
||||
.fail(function () {
|
||||
$('#band-invitee-input').attr("placeholder", "Unable to lookup friends");
|
||||
app.ajaxError(arguments)
|
||||
});
|
||||
}
|
||||
|
||||
function loadGenres(selectedGenres) {
|
||||
$("#band-genres").empty();
|
||||
|
||||
|
|
@ -393,13 +359,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
function friendSelectorCallback(newSelections) {
|
||||
var keys = Object.keys(newSelections);
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
addInvitation(newSelections[keys[i]].userName, newSelections[keys[i]].userId);
|
||||
}
|
||||
}
|
||||
|
||||
function addInvitation(value, data) {
|
||||
if ($('#selected-band-invitees div[user-id=' + data + ']').length === 0) {
|
||||
var template = $('#template-band-invitation').html();
|
||||
|
|
@ -462,10 +421,6 @@
|
|||
|
||||
$('#btn-band-setup-save').click(saveBand);
|
||||
|
||||
$('#btn-band-choose-friends').click(function () {
|
||||
friendSelectorDialog.showDialog(selectedFriendIds);
|
||||
});
|
||||
|
||||
$('#band-country').on('change', function (evt) {
|
||||
evt.stopPropagation();
|
||||
loadRegions();
|
||||
|
|
@ -493,10 +448,13 @@
|
|||
$('div[layout-id="band/setup"] .btn-facebook-invitation').click(function () {
|
||||
invitationDialog.showFacebookDialog();
|
||||
});
|
||||
|
||||
$(friendInput).focus(function() { $(this).val(''); })
|
||||
}
|
||||
|
||||
function initialize(invitationDialogInstance, friendSelectorDialogInstance) {
|
||||
friendSelectorDialog = friendSelectorDialogInstance;
|
||||
function initialize(invitationDialogInstance, inviteMusiciansUtilInstance) {
|
||||
inviteMusiciansUtil = inviteMusiciansUtilInstance;
|
||||
friendInput = inviteMusiciansUtil.inviteBandCreate('#band-setup-invite-musicians', "<div class='left w70'>If your bandmates are already on JamKazam, start typing their names in the box below, or click the Choose Friends button to select them.</div>");
|
||||
invitationDialog = invitationDialogInstance;
|
||||
events();
|
||||
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@
|
|||
self.updatingBandPhoto = true;
|
||||
renderBandPhotoSpinner();
|
||||
|
||||
console.log("Converting...");
|
||||
logger.debug("Converting...");
|
||||
|
||||
// we convert two times; first we crop to the selected region,
|
||||
// then we scale to 88x88 (targetCropSize X targetCropSize), which is the largest size we use throughout the site.
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
function cancelUpdate(e) {
|
||||
if ((e.ctrlKey || e.metaKey) && e.keyCode == 78) {
|
||||
console.log("update canceled!");
|
||||
logger.debug("update canceled!");
|
||||
app.layout.closeDialog('client-update');
|
||||
app.clientUpdating = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
//= require jquery
|
||||
//= require jquery.queryparams
|
||||
//= require AAA_Log
|
||||
//= require AAC_underscore
|
||||
//= require globals
|
||||
//= require jamkazam
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
var inviteMusiciansUtil = null;
|
||||
var MAX_GENRES = 1;
|
||||
var sessionSettings = {};
|
||||
var friendInput = null;
|
||||
|
||||
function beforeShow(data) {
|
||||
inviteMusiciansUtil.clearSelections();
|
||||
|
|
@ -60,7 +61,7 @@
|
|||
context.JK.dropdown($('#musician-access', $form));
|
||||
context.JK.dropdown($('#fan-access', $form));
|
||||
|
||||
$('#friend-input')
|
||||
$(friendInput)
|
||||
.unbind('blur')
|
||||
.attr("placeholder", "Looking up friends...")
|
||||
.prop('disabled', true)
|
||||
|
|
@ -233,7 +234,7 @@
|
|||
invitationDialog.showFacebookDialog(e);
|
||||
});
|
||||
|
||||
$('#friend-input').focus(function() { $(this).val(''); })
|
||||
$(friendInput).focus(function() { $(this).val(''); })
|
||||
}
|
||||
|
||||
function toggleMusicianAccess() {
|
||||
|
|
@ -306,7 +307,7 @@
|
|||
function initialize(invitationDialogInstance, inviteMusiciansUtilInstance) {
|
||||
invitationDialog = invitationDialogInstance;
|
||||
inviteMusiciansUtil = inviteMusiciansUtilInstance;
|
||||
inviteMusiciansUtil.inviteSessionCreate('#create-session-invite-musicians');
|
||||
friendInput = inviteMusiciansUtil.inviteSessionCreate('#create-session-invite-musicians', "<div style='margin-right:140px;'>Start typing friends' names or:</div>"); //'
|
||||
events();
|
||||
loadBands();
|
||||
loadSessionSettings();
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
function handle_fblogin_response(response) {
|
||||
|
||||
console.log("facebook login response: status=" + response.status)
|
||||
logger.debug("facebook login response: status=" + response.status)
|
||||
|
||||
if(response.status == "connected") {
|
||||
connected = true;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
var instrument_logo_map = context.JK.getInstrumentIconMap24();
|
||||
var did_show_musician_page = false;
|
||||
var page_num=1, page_count=0;
|
||||
var textMessageDialog = null;
|
||||
|
||||
function loadMusicians(queryString) {
|
||||
// squelch nulls and undefines
|
||||
|
|
@ -86,27 +87,27 @@
|
|||
var mTemplate = $('#template-find-musician-row').html();
|
||||
var fTemplate = $('#template-musician-follow-info').html();
|
||||
var aTemplate = $('#template-musician-action-btns').html();
|
||||
var mVals, mm, renderings='';
|
||||
var mVals, musician, renderings='';
|
||||
var instr_logos, instr;
|
||||
var follows, followVals, aFollow;
|
||||
|
||||
for (ii=0, len=musicians.length; ii < len; ii++) {
|
||||
mm = musicians[ii];
|
||||
if (context.JK.currentUserId === mm.id) {
|
||||
musician = musicians[ii];
|
||||
if (context.JK.currentUserId === musician.id) {
|
||||
// VRFS-294.3 (David) => skip if current user is musician
|
||||
continue;
|
||||
}
|
||||
instr_logos = '';
|
||||
for (var jj=0, ilen=mm['instruments'].length; jj<ilen; jj++) {
|
||||
if (mm['instruments'][jj].instrument_id in instrument_logo_map) {
|
||||
instr = instrument_logo_map[mm['instruments'][jj].instrument_id];
|
||||
for (var jj=0, ilen=musician['instruments'].length; jj<ilen; jj++) {
|
||||
if (musician['instruments'][jj].instrument_id in instrument_logo_map) {
|
||||
instr = instrument_logo_map[musician['instruments'][jj].instrument_id];
|
||||
}
|
||||
instr_logos += '<img src="' + instr + '"/>';
|
||||
}
|
||||
follows = '';
|
||||
followVals = {};
|
||||
for (var jj=0, ilen=mm['followings'].length; jj<ilen; jj++) {
|
||||
aFollow = mm['followings'][jj];
|
||||
for (var jj=0, ilen=musician['followings'].length; jj<ilen; jj++) {
|
||||
aFollow = musician['followings'][jj];
|
||||
followVals = {
|
||||
user_id: aFollow.user_id,
|
||||
musician_name: aFollow.name,
|
||||
|
|
@ -117,27 +118,29 @@
|
|||
if (2 == jj) break;
|
||||
}
|
||||
var actionVals = {
|
||||
profile_url: "/client#/profile/" + mm.id,
|
||||
friend_class: 'button-' + (mm['is_friend'] ? 'grey' : 'orange'),
|
||||
friend_caption: (mm.is_friend ? 'DIS':'')+'CONNECT',
|
||||
follow_class: 'button-' + (mm['is_following'] ? 'grey' : 'orange'),
|
||||
follow_caption: (mm.is_following ? 'UN':'')+'FOLLOW',
|
||||
profile_url: "/client#/profile/" + musician.id,
|
||||
friend_class: 'button-' + (musician['is_friend'] ? 'grey' : 'orange'),
|
||||
friend_caption: (musician.is_friend ? 'DIS':'')+'CONNECT',
|
||||
follow_class: 'button-' + (musician['is_following'] ? 'grey' : 'orange'),
|
||||
follow_caption: (musician.is_following ? 'UN':'')+'FOLLOW',
|
||||
message_class: 'button-orange',
|
||||
message_caption: 'MESSAGE',
|
||||
button_message: 'button-orange'
|
||||
};
|
||||
var musician_actions = context.JK.fillTemplate(aTemplate, actionVals);
|
||||
|
||||
mVals = {
|
||||
avatar_url: context.JK.resolveAvatarUrl(mm.photo_url),
|
||||
profile_url: "/client#/profile/" + mm.id,
|
||||
musician_name: mm.name,
|
||||
musician_location: mm.city + ', ' + mm.state,
|
||||
avatar_url: context.JK.resolveAvatarUrl(musician.photo_url),
|
||||
profile_url: "/client#/profile/" + musician.id,
|
||||
musician_name: musician.name,
|
||||
musician_location: musician.city + ', ' + musician.state,
|
||||
instruments: instr_logos,
|
||||
biography: mm['biography'],
|
||||
follow_count: mm['follow_count'],
|
||||
friend_count: mm['friend_count'],
|
||||
recording_count: mm['recording_count'],
|
||||
session_count: mm['session_count'],
|
||||
musician_id: mm['id'],
|
||||
biography: musician['biography'],
|
||||
follow_count: musician['follow_count'],
|
||||
friend_count: musician['friend_count'],
|
||||
recording_count: musician['recording_count'],
|
||||
session_count: musician['session_count'],
|
||||
musician_id: musician['id'],
|
||||
musician_follow_template: follows,
|
||||
musician_action_template: musician_actions
|
||||
};
|
||||
|
|
@ -148,6 +151,7 @@
|
|||
|
||||
$('.search-m-friend').on('click', friendMusician);
|
||||
$('.search-m-follow').on('click', followMusician);
|
||||
$('.search-m-message').on('click', messageMusician);
|
||||
|
||||
context.JK.bindHoverEvents();
|
||||
}
|
||||
|
|
@ -163,7 +167,7 @@
|
|||
|
||||
function clearResults() {
|
||||
musicians = {};
|
||||
$('#musician-filter-results').empty();
|
||||
$('#musician-filter-results .musician-list-result').remove();
|
||||
page_num = 1;
|
||||
page_count = 0;
|
||||
}
|
||||
|
|
@ -217,6 +221,12 @@
|
|||
});
|
||||
}
|
||||
|
||||
function messageMusician() {
|
||||
var userId = $(this).parent().data('musician-id');
|
||||
app.layout.showDialog('text-message', { d1: userId });
|
||||
return false;
|
||||
}
|
||||
|
||||
function events() {
|
||||
$('#musician_query_distance').change(refreshDisplay);
|
||||
$('#musician_instrument').change(refreshDisplay);
|
||||
|
|
@ -228,11 +238,17 @@
|
|||
page_num += 1;
|
||||
search();
|
||||
}
|
||||
else {
|
||||
$('#end-of-musician-list').show()
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
function initialize(textMessageDialogInstance) {
|
||||
|
||||
textMessageDialog = textMessageDialogInstance;
|
||||
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
|
|
|
|||
|
|
@ -692,7 +692,7 @@
|
|||
}
|
||||
|
||||
function newFtueSave(persist) {
|
||||
console.log("newFtueSave persist(" + persist + ")")
|
||||
logger.debug("newFtueSave persist(" + persist + ")")
|
||||
newFtueUpdateLatencyView('loading');
|
||||
logger.debug("Calling FTUESave(" + persist + ")");
|
||||
jamClient.FTUESave(persist);
|
||||
|
|
|
|||
|
|
@ -21,16 +21,16 @@
|
|||
function switchClientMode(e) {
|
||||
// ctrl + shift + 0
|
||||
if(e.ctrlKey && e.shiftKey && e.keyCode == 48) {
|
||||
console.log("switch client mode!");
|
||||
logger.debug("switch client mode!");
|
||||
var act_as_native_client = $.cookie('act_as_native_client');
|
||||
|
||||
console.log("currently: " + act_as_native_client);
|
||||
logger.debug("currently: " + act_as_native_client);
|
||||
if(act_as_native_client == null || act_as_native_client != "true") {
|
||||
console.log("forcing act as native client!");
|
||||
logger.debug("forcing act as native client!");
|
||||
$.cookie('act_as_native_client', 'true', { expires: 120, path: '/' });
|
||||
}
|
||||
else {
|
||||
console.log("remove act as native client!");
|
||||
logger.debug("remove act as native client!");
|
||||
$.removeCookie('act_as_native_client');
|
||||
}
|
||||
window.location.reload();
|
||||
|
|
|
|||
|
|
@ -108,11 +108,13 @@
|
|||
function configureActionButtons(user) {
|
||||
var btnFriendSelector = "#btnFriend";
|
||||
var btnFollowSelector = "#btnFollow";
|
||||
var btnMessageSelector = '#btnMessage';
|
||||
|
||||
// if unauthenticated or authenticated user is viewing his own profile
|
||||
if (!context.JK.currentUserId || context.JK.currentUserId === user.id) {
|
||||
$(btnFriendSelector, hoverSelector).hide();
|
||||
$(btnFollowSelector, hoverSelector).hide();
|
||||
$(btnMessageSelector, hoverSelector).hide();
|
||||
}
|
||||
else {
|
||||
if (user.is_friend) {
|
||||
|
|
@ -125,6 +127,7 @@
|
|||
$(btnFriendSelector, hoverSelector).hide();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.hideBubble = function() {
|
||||
|
|
|
|||
|
|
@ -201,9 +201,9 @@
|
|||
description: '',
|
||||
actions: [{ name: 'Signup', link: signupUrl }]
|
||||
};
|
||||
console.log("facebook feed options:", obj);
|
||||
logger.debug("facebook feed options:", obj);
|
||||
function fbFeedDialogCallback(response) {
|
||||
//console.log("feedback dialog closed: " + response['post_id'])
|
||||
//logger.debug("feedback dialog closed: " + response['post_id'])
|
||||
if (response && response['post_id']) {
|
||||
context.JK.GA.trackServiceInvitations(context.JK.GA.InvitationTypes.facebook, 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,18 +14,34 @@
|
|||
var autoComplete = null;
|
||||
var rest = context.JK.Rest();
|
||||
var inviteAction = 'create'; // create/update
|
||||
var friendInput = null;
|
||||
var updateSessionID = null;
|
||||
var addInstructions = '';
|
||||
|
||||
this.inviteSessionCreate = function(elemSelector) {
|
||||
inviteAction = 'create';
|
||||
function _initInvite(elemSelector, iAction, instructions) {
|
||||
addInstructions = instructions;
|
||||
inviteAction = iAction;
|
||||
friendInput = '#friend-input-'+inviteAction;
|
||||
_appendFriendSelector($(elemSelector));
|
||||
return friendInput;
|
||||
}
|
||||
|
||||
this.inviteSessionCreate = function(elemSelector, instructions) {
|
||||
return _initInvite(elemSelector, 'create', instructions)
|
||||
};
|
||||
|
||||
this.inviteBandCreate = function(elemSelector, instructions) {
|
||||
return _initInvite(elemSelector, 'band', instructions)
|
||||
};
|
||||
|
||||
this.inviteSessionUpdate = function(elemSelector, sessionId) {
|
||||
this.clearSelections();
|
||||
updateSessionID = sessionId;
|
||||
friendSelectorDialog.setCallback(friendSelectorCallback);
|
||||
|
||||
inviteAction = 'update';
|
||||
friendInput = '#friend-input-'+inviteAction;
|
||||
|
||||
if (0 == $(elemSelector + ' .friendbox').length) {
|
||||
_appendFriendSelector($(elemSelector));
|
||||
$('#btn-save-invites').click(function() {
|
||||
|
|
@ -52,6 +68,7 @@
|
|||
existingInvites = [];
|
||||
updateSessionID = null;
|
||||
$('.selected-friends').empty();
|
||||
$(friendInput).val('');
|
||||
};
|
||||
|
||||
this.loadFriends = function() {
|
||||
|
|
@ -64,27 +81,21 @@
|
|||
userIds.push(this.id);
|
||||
userPhotoUrls.push(this.photo_url);
|
||||
});
|
||||
|
||||
var autoCompleteOptions = {
|
||||
lookup: { suggestions: userNames, data: userIds },
|
||||
onSelect: addInvitation,
|
||||
serviceUrl: '/api/search.json?srch_sessinv=1',
|
||||
minChars: 3,
|
||||
autoSelectFirst: true
|
||||
};
|
||||
|
||||
$('#friend-input').attr("placeholder", "Type a friend\'s name").prop('disabled', false);
|
||||
|
||||
if (!autoComplete) {
|
||||
autoComplete = $('#friend-input').autocomplete(autoCompleteOptions);
|
||||
} else {
|
||||
autoComplete.setOptions(autoCompleteOptions);
|
||||
if (friendInput) {
|
||||
var autoCompleteOptions = {
|
||||
lookup: { suggestions: userNames, data: userIds },
|
||||
onSelect: addInvitation,
|
||||
serviceUrl: '/api/search.json?srch_sessinv=1',
|
||||
minChars: 3,
|
||||
autoSelectFirst: true
|
||||
};
|
||||
$(friendInput).attr("placeholder", "Type a friend\'s name").prop('disabled', false)
|
||||
autoComplete = $(friendInput).autocomplete(autoCompleteOptions);
|
||||
$(".autocomplete").width("150px");
|
||||
}
|
||||
|
||||
$(".autocomplete").width("150px");
|
||||
})
|
||||
.fail(function() {
|
||||
$('#friend-input').attr("placeholder", "Unable to lookup friends");
|
||||
$(friendInput).attr("placeholder", "Unable to lookup friends");
|
||||
app.ajaxError(arguments);
|
||||
});
|
||||
}
|
||||
|
|
@ -114,11 +125,11 @@
|
|||
userName: value,
|
||||
imageStyle: imgStyle});
|
||||
$('.selected-friends').append(invitationHtml);
|
||||
$('#friend-input').select();
|
||||
$(friendInput).select();
|
||||
invitedFriends.push(data);
|
||||
|
||||
} else {
|
||||
$('#friend-input').select();
|
||||
$(friendInput).select();
|
||||
context.alert('Invitation already exists for this musician.');
|
||||
}
|
||||
}
|
||||
|
|
@ -188,9 +199,12 @@
|
|||
}
|
||||
|
||||
function _friendSelectorHTML() {
|
||||
var fInput = friendInput ? friendInput.substring(1,friendInput.length) : '';
|
||||
return context.JK.fillTemplate($('#template-session-invite-musicians').html(),
|
||||
{choose_friends_id: 'btn-choose-friends-'+inviteAction,
|
||||
selected_friends_id: 'selected-friends-'+inviteAction});
|
||||
selected_friends_id: 'selected-friends-'+inviteAction,
|
||||
friend_input: fInput,
|
||||
instructions: addInstructions});
|
||||
}
|
||||
|
||||
function _appendFriendSelector(elemSelector) {
|
||||
|
|
@ -201,10 +215,14 @@
|
|||
invitedFriends.map(function(uid) { obj[uid] = true; });
|
||||
friendSelectorDialog.showDialog(obj);
|
||||
});
|
||||
if ('update' == inviteAction) {
|
||||
$(friendInput).hide();
|
||||
}
|
||||
};
|
||||
|
||||
this.initialize = function(friendSelectorDialogInstance) {
|
||||
friendSelectorDialog = friendSelectorDialogInstance;
|
||||
return this;
|
||||
};
|
||||
|
||||
return this;
|
||||
|
|
|
|||
|
|
@ -576,7 +576,7 @@
|
|||
|
||||
/** check if the server is alive */
|
||||
function serverHealthCheck(options) {
|
||||
console.log("serverHealthCheck")
|
||||
logger.debug("serverHealthCheck")
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
url: "/api/versioncheck"
|
||||
|
|
@ -907,6 +907,27 @@
|
|||
});
|
||||
}
|
||||
|
||||
function createTextMessage(options) {
|
||||
var id = getId(options);
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
url: '/api/users/' + id + '/notifications',
|
||||
dataType: "json",
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(options)
|
||||
});
|
||||
}
|
||||
|
||||
function getNotifications(options) {
|
||||
var id = getId(options);
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
url: '/api/users/' + id + '/notifications?' + $.param(options),
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
return self;
|
||||
}
|
||||
|
|
@ -986,6 +1007,8 @@
|
|||
this.getShareRecording = getShareRecording;
|
||||
this.tweet = tweet;
|
||||
this.createFbInviteUrl = createFbInviteUrl;
|
||||
this.createTextMessage = createTextMessage;
|
||||
this.getNotifications = getNotifications;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
var JamKazam = context.JK.JamKazam = function () {
|
||||
var app;
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var heartbeatInterval = null;
|
||||
var heartbeatMS = null;
|
||||
var heartbeatMissedMS = 10000; // if 5 seconds go by and we haven't seen a heartbeat ack, get upset
|
||||
|
|
@ -26,6 +27,7 @@
|
|||
var lastHeartbeatAckTime = null;
|
||||
var lastHeartbeatFound = false;
|
||||
var heartbeatAckCheckInterval = null;
|
||||
var userDeferred = null;
|
||||
|
||||
var opts = {
|
||||
inClient: true, // specify false if you want the app object but none of the client-oriented features
|
||||
|
|
@ -57,6 +59,10 @@
|
|||
}
|
||||
rules[target] = {route: '/' + targetUrl + '/:d?', method: target};
|
||||
routingContext[target] = fn;
|
||||
|
||||
// allow dialogs to take an optional argument
|
||||
rules[target+'opt'] = {route: '/' + targetUrl + '/:d?/d1:', method: target};
|
||||
routingContext[target + 'opt'] = fn;
|
||||
});
|
||||
routes.context(routingContext);
|
||||
for (rule in rules) if (rules.hasOwnProperty(rule)) routes.add(rules[rule]);
|
||||
|
|
@ -214,7 +220,7 @@
|
|||
var errorResponse = JSON.parse(jqXHR.responseText)["errors"];
|
||||
for (var key in errorResponse) {
|
||||
var errorsForKey = errorResponse[key];
|
||||
console.log("key: " + key);
|
||||
logger.debug("key: " + key);
|
||||
var prettyKey = context.JK.entityToPrintable[key];
|
||||
if (!prettyKey) {
|
||||
prettyKey = key;
|
||||
|
|
@ -296,7 +302,7 @@
|
|||
if (jqXHR.status == 422) {
|
||||
var errors = JSON.parse(jqXHR.responseText);
|
||||
var $errors = context.JK.format_all_errors(errors);
|
||||
console.log("Unprocessable entity sent from server:", errors)
|
||||
logger.debug("Unprocessable entity sent from server:", errors)
|
||||
this.notify({title: title, text: $errors, icon_url: "/assets/content/icon_alert_big.png"})
|
||||
}
|
||||
else {
|
||||
|
|
@ -311,7 +317,7 @@
|
|||
if(bodyIndex > -1) {
|
||||
text = text.substr(bodyIndex);
|
||||
}
|
||||
console.log("html", text);
|
||||
logger.debug("html", text);
|
||||
$('#server-error-dialog .error-contents').html(text);
|
||||
app.layout.showDialog('server-error-dialog')
|
||||
return false;
|
||||
|
|
@ -356,7 +362,7 @@
|
|||
context.RouteMap.parse(hash);
|
||||
}
|
||||
catch (e) {
|
||||
console.log("ignoring bogus screen name: %o", hash)
|
||||
logger.debug("ignoring bogus screen name: %o", hash)
|
||||
hash = null;
|
||||
}
|
||||
|
||||
|
|
@ -369,6 +375,10 @@
|
|||
context.location = url;
|
||||
}
|
||||
|
||||
// call .done/.fail on this to wait for safe user data
|
||||
this.user = function() {
|
||||
return userDeferred;
|
||||
}
|
||||
|
||||
this.unloadFunction = function () {
|
||||
logger.debug("window.unload function called.");
|
||||
|
|
@ -395,6 +405,8 @@
|
|||
events();
|
||||
this.layout.handleDialogState();
|
||||
|
||||
userDeferred = rest.getUserDetail();
|
||||
|
||||
if (opts.inClient) {
|
||||
registerLoginAck();
|
||||
registerHeartbeatAck();
|
||||
|
|
@ -404,6 +416,10 @@
|
|||
registerDownloadAvailable();
|
||||
context.JK.FaderHelpers.initialize();
|
||||
context.window.onunload = this.unloadFunction;
|
||||
|
||||
userDeferred.fail(function(jqXHR) {
|
||||
app.notify({title: "Unable to Load User", text: "You should reload the page."})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
//= require jquery
|
||||
//= require jquery.queryparams
|
||||
//= require AAA_Log
|
||||
//= require AAC_underscore
|
||||
//= require globals
|
||||
//= require jamkazam
|
||||
|
|
|
|||
|
|
@ -418,7 +418,7 @@
|
|||
}
|
||||
|
||||
function closeDialog(dialog) {
|
||||
console.log("closing dialog: " + dialog);
|
||||
logger.debug("closing dialog: " + dialog);
|
||||
var $dialog = $('[layout-id="' + dialog + '"]');
|
||||
dialogEvent(dialog, 'beforeHide');
|
||||
var $overlay = $('.dialog-overlay');
|
||||
|
|
@ -468,7 +468,7 @@
|
|||
var screen = location.page.substring(1); // remove leading slash
|
||||
var accepted = screenEvent(currentScreen, 'beforeLeave', {screen:screen, hash: context.location.hash});
|
||||
if(accepted === false) {
|
||||
console.log("navigation to " + context.location.hash + " rejected by " + currentScreen);
|
||||
logger.debug("navigation to " + context.location.hash + " rejected by " + currentScreen);
|
||||
//resettingHash = true;
|
||||
// reset the hash to where it just was
|
||||
context.location.hash = currentHash;
|
||||
|
|
@ -497,6 +497,7 @@
|
|||
|
||||
logger.debug("Changing screen to " + currentScreen);
|
||||
|
||||
logger.debug("data: ", data);
|
||||
screenEvent(currentScreen, 'beforeShow', data);
|
||||
|
||||
// For now -- it seems we want it open always.
|
||||
|
|
@ -522,7 +523,7 @@
|
|||
|
||||
// Show any requested dialog
|
||||
if ("d" in data) {
|
||||
showDialog(data.d);
|
||||
showDialog(data.d, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -575,7 +576,7 @@
|
|||
}
|
||||
|
||||
function showDialog(dialog, options) {
|
||||
if (!dialogEvent(dialog, 'beforeShow')) {
|
||||
if (!dialogEvent(dialog, 'beforeShow', options)) {
|
||||
return;
|
||||
}
|
||||
var $overlay = $('.dialog-overlay')
|
||||
|
|
@ -593,7 +594,7 @@
|
|||
var $dialog = $('[layout-id="' + dialog + '"]');
|
||||
stackDialogs($dialog, $overlay);
|
||||
$dialog.show();
|
||||
dialogEvent(dialog, 'afterShow');
|
||||
dialogEvent(dialog, 'afterShow', options);
|
||||
}
|
||||
|
||||
function centerDialog(dialog) {
|
||||
|
|
@ -845,8 +846,8 @@
|
|||
return onHashChange(e, postFunction);
|
||||
}
|
||||
|
||||
this.showDialog = function (dialog) {
|
||||
showDialog(dialog);
|
||||
this.showDialog = function (dialog, options) {
|
||||
showDialog(dialog, options);
|
||||
};
|
||||
|
||||
this.close = function (evt) {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@
|
|||
});
|
||||
}
|
||||
else {
|
||||
console.log("workin fool: %o", working)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@
|
|||
|
||||
$playmodeButton.on('ifChecked', function(e) {
|
||||
var playmode = $(this).val();
|
||||
console.log("set new playmode", playmode);
|
||||
logger.debug("set new playmode", playmode);
|
||||
setPlaybackMode(playmode);
|
||||
});
|
||||
|
||||
|
|
@ -160,7 +160,7 @@
|
|||
}
|
||||
|
||||
// at the end of the play, the duration sets to 0, as does currentTime. but isPlaying does not reset to
|
||||
console.log("currentTimeMs, durationTimeMs", currentTimeMs, durationTimeMs);
|
||||
logger.debug("currentTimeMs, durationTimeMs", currentTimeMs, durationTimeMs);
|
||||
if(currentTimeMs == 0 && durationTimeMs == 0) {
|
||||
if(isPlaying) {
|
||||
isPlaying = false;
|
||||
|
|
@ -168,7 +168,7 @@
|
|||
currentTimeMs = playbackDurationMs;
|
||||
stopPlay();
|
||||
endReached = true;
|
||||
console.log("end reached");
|
||||
logger.debug("end reached");
|
||||
}
|
||||
else {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
var decrementedFriendCountOnce = false;
|
||||
var sentFriendRequest = false;
|
||||
var profileScreen = null;
|
||||
var textMessageDialog = null;
|
||||
|
||||
var instrument_logo_map = context.JK.getInstrumentIconMap24();
|
||||
|
||||
|
|
@ -110,6 +111,7 @@
|
|||
$('#btn-profile-edit').show();
|
||||
$('#btn-add-friend').hide();
|
||||
$('#btn-follow-user').hide();
|
||||
$('#btn-message-user').hide();
|
||||
}
|
||||
else {
|
||||
configureFriendFollowersControls();
|
||||
|
|
@ -117,6 +119,7 @@
|
|||
$('#btn-profile-edit').hide();
|
||||
$('#btn-add-friend').show();
|
||||
$('#btn-follow-user').show();
|
||||
$('#btn-message-user').show();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,6 +154,7 @@
|
|||
// this doesn't need deferred because it's only shown when valid
|
||||
$('#btn-add-friend').click(handleFriendChange);
|
||||
$('#btn-follow-user').click(handleFollowingChange);
|
||||
$('#btn-message-user').click(handleMessageMusician);
|
||||
}
|
||||
|
||||
function handleFriendChange(evt) {
|
||||
|
|
@ -160,6 +164,7 @@
|
|||
else {
|
||||
sendFriendRequest(evt);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function handleFollowingChange(evt) {
|
||||
|
|
@ -169,6 +174,12 @@
|
|||
else {
|
||||
addFollowing();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function handleMessageMusician(evt) {
|
||||
app.layout.showDialog('text-message', { d1: userId });
|
||||
return false;
|
||||
}
|
||||
|
||||
function sendFriendRequest(evt) {
|
||||
|
|
@ -741,7 +752,8 @@
|
|||
function bindFavorites() {
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
function initialize(textMessageDialogInstance) {
|
||||
textMessageDialog = textMessageDialogInstance;
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@
|
|||
|
||||
timeCallback();
|
||||
|
||||
console.log("alert callback", type, text);
|
||||
logger.debug("alert callback", type, text);
|
||||
|
||||
if (type === 2) { // BACKEND_MIXER_CHANGE
|
||||
logger.debug("BACKEND_MIXER_CHANGE alert. reason:" + text);
|
||||
|
|
@ -904,7 +904,7 @@
|
|||
lookingForMixers[track.id] = participant.client_id;
|
||||
trackData.noaudio = true;
|
||||
if (!(lookingForMixersTimer)) {
|
||||
console.log("waiting for mixer to show up for track: " + track.id)
|
||||
logger.debug("waiting for mixer to show up for track: " + track.id)
|
||||
lookingForMixersTimer = context.setInterval(lookForMixers, 500);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,10 +59,10 @@
|
|||
var jsFunction = "JK.Callbacks.clientPingResponse";
|
||||
var timeoutFunction = "JK.Callbacks.clientPingTimeout";
|
||||
|
||||
console.log("jamClient.TestLatency")
|
||||
console.time('jamClient.TestLatency');
|
||||
logger.debug("jamClient.TestLatency")
|
||||
//console.time('jamClient.TestLatency');
|
||||
jamClient.TestLatency(clientID, jsFunction, timeoutFunction);
|
||||
console.timeEnd('jamClient.TestLatency');
|
||||
//console.timeEnd('jamClient.TestLatency');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -463,7 +463,7 @@
|
|||
})
|
||||
}
|
||||
else {
|
||||
console.log("no copy-to-clipboard capabilities")
|
||||
logger.debug("no copy-to-clipboard capabilities")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
var friends = [];
|
||||
var rest = context.JK.Rest();
|
||||
var invitationDialog = null;
|
||||
var textMessageDialog = null;
|
||||
|
||||
function initializeSearchPanel() {
|
||||
$('#search_text_type').change(function() {
|
||||
|
|
@ -139,6 +140,10 @@
|
|||
|
||||
$.each(response, function(index, val) {
|
||||
|
||||
if(val.description == 'TEXT_MESSAGE') {
|
||||
val.formatted_msg = textMessageDialog.formatTextMessage(val.message.substring(0, 200), val.source_user_id, val.source_user.name, val.message.length > 200).html();
|
||||
}
|
||||
|
||||
// fill in template for Connect pre-click
|
||||
var template = $('#template-notification-panel').html();
|
||||
var notificationHtml = context.JK.fillTemplate(template, {
|
||||
|
|
@ -263,6 +268,30 @@
|
|||
else if (type === context.JK.MessageType.BAND_INVITATION_ACCEPTED) {
|
||||
$notification.find('#div-actions').hide();
|
||||
}
|
||||
else if (type === context.JK.MessageType.TEXT_MESSAGE) {
|
||||
var $action_btn = $notification.find($btnNotificationAction);
|
||||
$action_btn.text('REPLY');
|
||||
$action_btn.click(function() {
|
||||
var userId = $notification.find('.more-text-available').attr('data-sender-id');
|
||||
app.layout.showDialog('text-message', { d1: userId });
|
||||
});
|
||||
|
||||
var moreTextLink = $notification.find('.more-text-available');
|
||||
var textMessage = $notification.find('.text-message');
|
||||
var clipped_msg = textMessage.attr('data-is-clipped') === 'true';
|
||||
|
||||
if(clipped_msg) {
|
||||
moreTextLink.text('more').show();
|
||||
moreTextLink.click(function(e) {
|
||||
var userId = $(this).attr('data-sender-id');
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
moreTextLink.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function deleteNotificationHandler(evt) {
|
||||
|
|
@ -350,8 +379,13 @@
|
|||
|
||||
// default handler for incoming notification
|
||||
function handleNotification(payload, type) {
|
||||
var sidebarText;
|
||||
sidebarText = payload.msg;
|
||||
|
||||
// on a load of notifications, it is possible to load a very new notification,
|
||||
// and get a websocket notification right after for that same notification,
|
||||
// so we need to protect against such duplicates
|
||||
if($('#sidebar-notification-list').find('li[notification-id="' + payload.notification_id + '"]').length > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// increment displayed notification count
|
||||
incrementNotificationCount();
|
||||
|
|
@ -359,16 +393,18 @@
|
|||
// add notification to sidebar
|
||||
var template = $("#template-notification-panel").html();
|
||||
var notificationHtml = context.JK.fillTemplate(template, {
|
||||
notificationId: payload.notification_id,
|
||||
notificationId: payload.notification_id,
|
||||
sessionId: payload.session_id,
|
||||
avatar_url: context.JK.resolveAvatarUrl(payload.photo_url),
|
||||
text: sidebarText,
|
||||
text: payload.msg instanceof jQuery ? payload.msg.html() : payload.msg ,
|
||||
date: $.timeago(payload.created_at)
|
||||
});
|
||||
|
||||
$('#sidebar-notification-list').prepend(notificationHtml);
|
||||
|
||||
initializeActions(payload, type);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
var delay = (function(){
|
||||
|
|
@ -461,6 +497,9 @@
|
|||
registerSourceUp();
|
||||
registerSourceDown();
|
||||
|
||||
// register text messages
|
||||
registerTextMessage();
|
||||
|
||||
// watch for Invite More Users events
|
||||
$('#sidebar-div .btn-email-invitation').click(function() {
|
||||
invitationDialog.showEmailDialog();
|
||||
|
|
@ -1000,9 +1039,19 @@
|
|||
args.band_id,
|
||||
args.band_invitation_id,
|
||||
true
|
||||
).done(function(response) {
|
||||
).done(function(response) {
|
||||
deleteNotification(args.notification_id); // delete notification corresponding to this friend request
|
||||
}).error(app.ajaxError);
|
||||
}).error(app.ajaxError);
|
||||
}
|
||||
|
||||
function registerTextMessage() {
|
||||
context.JK.JamServer.registerMessageCallback(context.JK.MessageType.TEXT_MESSAGE, function(header, payload) {
|
||||
logger.debug("Handling TEXT_MESSAGE msg " + JSON.stringify(payload));
|
||||
|
||||
textMessageDialog.messageReceived(payload);
|
||||
|
||||
handleNotification(payload, header.type);
|
||||
});
|
||||
}
|
||||
|
||||
function registerBandInvitationAccepted() {
|
||||
|
|
@ -1124,13 +1173,14 @@
|
|||
});
|
||||
}
|
||||
|
||||
this.initialize = function(invitationDialogInstance) {
|
||||
this.initialize = function(invitationDialogInstance, textMessageDialogInstance) {
|
||||
events();
|
||||
initializeSearchPanel();
|
||||
initializeFriendsPanel();
|
||||
initializeChatPanel();
|
||||
initializeNotificationsPanel();
|
||||
invitationDialog = invitationDialogInstance;
|
||||
textMessageDialog = textMessageDialogInstance;
|
||||
};
|
||||
}
|
||||
})(window,jQuery);
|
||||
|
|
@ -0,0 +1,259 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.TextMessageDialog = function(app) {
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var $dialog = null;
|
||||
var $previousMessages = null;
|
||||
var $previousMessagesScroller = null;
|
||||
var $sendTextMessage = null;
|
||||
var $form = null;
|
||||
var $textBox = null;
|
||||
var userLookup = null;
|
||||
var otherId = null;
|
||||
var offset = 0;
|
||||
var sendingMessage = false;
|
||||
var LIMIT = 20;
|
||||
var showing = false;
|
||||
var fullyInitialized = false;
|
||||
var user = null;
|
||||
var renderQueue = []; // to handle race condition between dialog showing and populated using REST, and messages coming in
|
||||
|
||||
var remainingCap = 400;
|
||||
|
||||
function reset() {
|
||||
fullyInitialized = false;
|
||||
renderQueue = [];
|
||||
sendingMessage = false;
|
||||
offset = 0;
|
||||
userLookup = {};
|
||||
$previousMessages.empty();
|
||||
$textBox.val('');
|
||||
$sendTextMessage.unbind('click');
|
||||
}
|
||||
|
||||
function buildParams() {
|
||||
return { type: 'TEXT_MESSAGE', receiver: otherId, offset: offset, limit: LIMIT};
|
||||
}
|
||||
|
||||
function buildMessage() {
|
||||
var message = {};
|
||||
|
||||
message['message'] = $textBox.val();
|
||||
message['receiver'] = otherId;
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
function sendMessage(e) {
|
||||
|
||||
var msg = $textBox.val();
|
||||
if(!msg || msg == '') {
|
||||
// don't bother the server with empty messages
|
||||
return;
|
||||
}
|
||||
|
||||
if(!sendingMessage) {
|
||||
sendingMessage = true;
|
||||
|
||||
$sendTextMessage.text('SENDING...')
|
||||
|
||||
rest.createTextMessage(buildMessage())
|
||||
.done(function() {
|
||||
$textBox.val('');
|
||||
renderMessage(msg, user.id, user.name, new Date().toISOString(), true);
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
app.notifyServerError(jqXHR, 'Unable to Send Message');
|
||||
})
|
||||
.always(function() {
|
||||
sendingMessage = false;
|
||||
$sendTextMessage.text('SEND');
|
||||
})
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function scrollToBottom(instant) {
|
||||
$previousMessagesScroller.animate({scrollTop: $previousMessagesScroller[0].scrollHeight}, instant ? 0 : 'slow');
|
||||
}
|
||||
|
||||
function renderMessage(msg, senderId, senderName, sent, append) {
|
||||
var options = {
|
||||
msg: msg,
|
||||
sender: senderId == user.id ? 'me' : senderName,
|
||||
sent: sent
|
||||
};
|
||||
var txt = $(context._.template($('#template-previous-message').html(), options, { variable: 'data' }));
|
||||
txt.find('.timeago').timeago();
|
||||
if(append) {
|
||||
$previousMessages.append(txt);
|
||||
scrollToBottom();
|
||||
}
|
||||
else {
|
||||
$previousMessages.prepend(txt);
|
||||
}
|
||||
}
|
||||
|
||||
function drainQueue() {
|
||||
context._.each(renderQueue, function(msg) {
|
||||
renderMessage(msg.msg, msg.senderId, msg.senderName, msg.sent, true);
|
||||
});
|
||||
renderQueue = [];
|
||||
}
|
||||
|
||||
function formatTextMessage(msg, sender_id, sender_name, clipped_msg) {
|
||||
var markedUpMsg = $('<span><span class="sender-name"></span> says: <span class="text-message"></span><a href="#" class="more-text-available"></a></span>');
|
||||
markedUpMsg.find('.sender-name').text(sender_name)
|
||||
markedUpMsg.find('.text-message').text(clipped_msg ? msg + "... " : msg).attr('data-is-clipped', clipped_msg)
|
||||
var moreTextLink = markedUpMsg.find('.more-text-available').attr('data-sender-id', sender_id);
|
||||
|
||||
if(clipped_msg) {
|
||||
moreTextLink.text('more').show();
|
||||
moreTextLink.click(function(e) {
|
||||
app.layout.showDialog('text-message', {d1: $(this).attr('data-sender-id')});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
moreTextLink.hide();
|
||||
}
|
||||
return markedUpMsg;
|
||||
}
|
||||
|
||||
function beforeShow(args) {
|
||||
|
||||
app.user()
|
||||
.done(function(userDetail) {
|
||||
user = userDetail;
|
||||
|
||||
var other = args.d1;
|
||||
|
||||
if(!other) throw "other must be specified in TextMessageDialog"
|
||||
otherId = other;
|
||||
|
||||
app.layout.closeDialog('text-message') // ensure no others are showing. this is a singleton dialog
|
||||
|
||||
showing = true;
|
||||
|
||||
userLookup[user.id] = user;
|
||||
|
||||
rest.getUserDetail({id: otherId})
|
||||
.done(function(otherUser) {
|
||||
|
||||
userLookup[otherUser.id] = otherUser;
|
||||
$dialog.find('.receiver-name').text(otherUser.name);
|
||||
$dialog.find('textarea').attr('placeholder', 'enter a message to ' + otherUser.name + '...');
|
||||
$dialog.find('.offline-tip').text('An email will be sent if ' + otherUser.name + ' is offline');
|
||||
$sendTextMessage.click(sendMessage);
|
||||
|
||||
rest.getNotifications(buildParams())
|
||||
.done(function(response) {
|
||||
context._.each(response, function(textMessage) {
|
||||
renderMessage(textMessage.message, textMessage.source_user_id, userLookup[textMessage.source_user_id].name, textMessage.created_at);
|
||||
})
|
||||
|
||||
scrollToBottom(true);
|
||||
fullyInitialized = true;
|
||||
drainQueue();
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
app.notifyServerError(jqXHR, 'Unable to Load Conversation')
|
||||
})
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
app.notifyServerError(jqXHR, 'Unable to Load Other User')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function afterHide() {
|
||||
showing = false;
|
||||
reset();
|
||||
}
|
||||
|
||||
function postMessage(e) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function events() {
|
||||
$form.submit(postMessage)
|
||||
}
|
||||
|
||||
|
||||
function respondTextInvitation(args) {
|
||||
app.layout.showDialog('text-message', {d1: args.sender_id}) ;
|
||||
}
|
||||
|
||||
// called from sidebar when messages come in
|
||||
function messageReceived(payload) {
|
||||
if(showing && otherId == payload.sender_id) {
|
||||
if(fullyInitialized) {
|
||||
renderMessage(payload.msg, payload.sender_id, payload.sender_name, payload.created_at, true);
|
||||
}
|
||||
else {
|
||||
// the dialog caught a message as it was initializing... queue it for later once dialog is showing
|
||||
renderQueue.push({msg: payload.msg, senderId: payload.sender_id, senderName: payload.sender_name, sent: msg.created_at});
|
||||
}
|
||||
}
|
||||
else {
|
||||
payload.msg = formatTextMessage(payload.msg, payload.sender_id, payload.sender_name, payload.clipped_msg);
|
||||
|
||||
app.notify({
|
||||
"title": "Message from " + payload.sender_name,
|
||||
"text": payload.msg,
|
||||
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url)
|
||||
}, {
|
||||
"ok_text": "REPLY",
|
||||
"ok_callback": respondTextInvitation,
|
||||
"ok_callback_args": {
|
||||
"sender_id": payload.sender_id,
|
||||
"notification_id": payload.notification_id
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
function showDialog(_other) {
|
||||
|
||||
app.layout.closeDialog('text-message') // this dialog is implemented as a singleton, so must enforce this
|
||||
|
||||
reset();
|
||||
|
||||
if(!_other) throw "other must be specified in TextMessageDialog"
|
||||
otherId = _other;
|
||||
|
||||
app.layout.showDialog('text-message')
|
||||
}*/
|
||||
|
||||
function initialize() {
|
||||
var dialogBindings = {
|
||||
'beforeShow' : beforeShow,
|
||||
'afterHide': afterHide
|
||||
};
|
||||
|
||||
|
||||
app.bindDialog('text-message', dialogBindings);
|
||||
|
||||
$dialog = $('#text-message-dialog');
|
||||
$previousMessagesScroller = $dialog.find('.previous-messages-scroller');
|
||||
$previousMessages = $dialog.find('.previous-messages');
|
||||
$sendTextMessage = $dialog.find('.btn-send-text-message');
|
||||
$form = $dialog.find('form');
|
||||
$textBox = $form.find('textarea');
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
this.messageReceived = messageReceived;
|
||||
this.formatTextMessage = formatTextMessage;
|
||||
}
|
||||
|
||||
return this;
|
||||
})(window,jQuery);
|
||||
|
|
@ -62,15 +62,14 @@
|
|||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '/api/users/' + context.JK.currentUserId
|
||||
}).done(function (r) {
|
||||
userMe = r;
|
||||
// TODO - Setting global variable for local user.
|
||||
context.JK.userMe = r;
|
||||
updateHeader();
|
||||
handleWhatsNext(userMe);
|
||||
}).fail(app.ajaxError);
|
||||
app.user()
|
||||
.done(function(r) {
|
||||
userMe = r;
|
||||
// TODO - Setting global variable for local user.
|
||||
context.JK.userMe = r;
|
||||
updateHeader();
|
||||
handleWhatsNext(userMe);
|
||||
});
|
||||
}
|
||||
|
||||
function updateHeader() {
|
||||
|
|
|
|||
|
|
@ -654,13 +654,13 @@
|
|||
|
||||
context.JK.hasOneConfiguredDevice = function() {
|
||||
var result = context.jamClient.FTUEGetGoodConfigurationList();
|
||||
console.log("hasOneConfiguredDevice: ", result);
|
||||
logger.debug("hasOneConfiguredDevice: ", result);
|
||||
return result.length > 0;
|
||||
};
|
||||
|
||||
context.JK.getGoodAudioConfigs = function() {
|
||||
var result = context.jamClient.FTUEGetGoodAudioConfigurations();
|
||||
console.log("goodAudioConfigs=%o", result);
|
||||
logger.debug("goodAudioConfigs=%o", result);
|
||||
return result;
|
||||
};
|
||||
|
||||
|
|
@ -685,7 +685,7 @@
|
|||
badAudioConfigs.push(allAudioConfigs[i]);
|
||||
}
|
||||
}
|
||||
console.log("badAudioConfigs=%o", badAudioConfigs);
|
||||
logger.debug("badAudioConfigs=%o", badAudioConfigs);
|
||||
return badAudioConfigs;
|
||||
};
|
||||
|
||||
|
|
@ -732,6 +732,12 @@
|
|||
return deviceId;
|
||||
}
|
||||
|
||||
// returns /client#/home for http://www.jamkazam.com/client#/home
|
||||
context.JK.locationPath = function() {
|
||||
var bits = context.location.href.split('/');
|
||||
return '/' + bits.slice(3).join('/');
|
||||
}
|
||||
|
||||
context.JK.nowUTC = function() {
|
||||
var d = new Date();
|
||||
return new Date( d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds() );
|
||||
|
|
|
|||
|
|
@ -25,7 +25,16 @@
|
|||
rest.login({email: email, password: password, remember_me: rememberMe})
|
||||
.done(function() {
|
||||
app.layout.closeDialog('signin-dialog')
|
||||
window.location = '/client'
|
||||
|
||||
var redirectTo = $.QueryString['redirect-to'];
|
||||
if(redirectTo) {
|
||||
logger.debug("redirectTo:" + redirectTo);
|
||||
window.location.href = redirectTo;
|
||||
}
|
||||
else {
|
||||
logger.debug("default post-login path");
|
||||
window.location.href = '/client'
|
||||
}
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
if(jqXHR.status == 422) {
|
||||
|
|
@ -62,6 +71,7 @@
|
|||
}
|
||||
|
||||
function beforeShow() {
|
||||
logger.debug("showing login form")
|
||||
reset();
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +80,7 @@
|
|||
}
|
||||
|
||||
function afterHide() {
|
||||
|
||||
logger.debug("hiding login form")
|
||||
}
|
||||
|
||||
function initialize(){
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
}
|
||||
else {
|
||||
var videoUrl = $.param.querystring(window.location.href, 'showVideo=' + encodeURIComponent($self.data('video-url')));
|
||||
console.log("videoUrl: ", videoUrl);
|
||||
context.jamClient.OpenSystemBrowser(videoUrl);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@
|
|||
//= require web/videoDialog
|
||||
//= require invitationDialog
|
||||
//= require tickDuration
|
||||
//= require hoverMusician
|
||||
//= require feed_item_recording
|
||||
//= require feed_item_session
|
||||
//= require hoverMusician
|
||||
//= require hoverFan
|
||||
//= require hoverBand
|
||||
//= require hoverSession
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
var welcomeRoot;
|
||||
var rest = context.JK.Rest();
|
||||
var logger = context.JK.logger;
|
||||
|
||||
function initialize() {
|
||||
|
||||
|
|
@ -22,7 +23,15 @@
|
|||
rest.getUserDetail({id:context.JK.currentUserId})
|
||||
.done(function () {
|
||||
e.preventDefault();
|
||||
window.location = '/client';
|
||||
var redirectTo = $.QueryString['redirect-to'];
|
||||
if(redirectTo) {
|
||||
logger.debug("redirectTo:" + redirectTo);
|
||||
window.location = redirectTo;
|
||||
}
|
||||
else {
|
||||
logger.debug("default post-login path");
|
||||
window.location = '/client';
|
||||
}
|
||||
})
|
||||
.fail(function () {
|
||||
context.JK.app.layout.showDialog('signin-dialog');
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
*= require ./localRecordingsDialog
|
||||
*= require ./serverErrorDialog
|
||||
*= require ./leaveSessionWarning
|
||||
*= require ./textMessageDialog
|
||||
*= require ./terms
|
||||
*= require ./createSession
|
||||
*= require ./feed
|
||||
|
|
|
|||
|
|
@ -429,7 +429,7 @@ ul.shortcuts {
|
|||
padding:2px;
|
||||
}
|
||||
|
||||
.account-home, .band-setup, .audio, .get-help, .download-app, .invite-friends {
|
||||
.account-home, .band-setup, .audio, .get-help, .download-app, .community-forum, .invite-friends {
|
||||
border-bottom:1px;
|
||||
border-style:solid;
|
||||
border-color:#ED3618;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@
|
|||
z-index:999;
|
||||
}
|
||||
|
||||
.bubble.musician-bubble {
|
||||
width:410px;
|
||||
}
|
||||
|
||||
.bubble h2 {
|
||||
padding:6px 0px;
|
||||
text-align:center;
|
||||
|
|
|
|||
|
|
@ -526,6 +526,26 @@ hr {
|
|||
margin: 10px 0;
|
||||
}
|
||||
|
||||
::-webkit-input-placeholder {
|
||||
font-family: Raleway, Arial, Helvetica, sans-serif;
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
:-moz-placeholder { /* Firefox 18- */
|
||||
font-family: Raleway, Arial, Helvetica, sans-serif;
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
::-moz-placeholder { /* Firefox 19+ */
|
||||
font-family: Raleway, Arial, Helvetica, sans-serif;
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
:-ms-input-placeholder {
|
||||
font-family: Raleway, Arial, Helvetica, sans-serif;
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
// infinitescroll required element
|
||||
.btn-next-pager {
|
||||
display:none;
|
||||
|
|
|
|||
|
|
@ -31,3 +31,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
#notification p .text-message {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
margin: 0 auto;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
left: 25%;
|
||||
left: 17%;
|
||||
width: 50%;
|
||||
z-index:-1;
|
||||
|
||||
|
|
|
|||
|
|
@ -261,5 +261,15 @@
|
|||
margin-left:-3px;
|
||||
}
|
||||
}
|
||||
|
||||
#sidebar-notification-list {
|
||||
|
||||
.text-message {
|
||||
word-wrap:break-word;
|
||||
}
|
||||
|
||||
.more-text-available {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
#text-message-dialog {
|
||||
width:500px;
|
||||
|
||||
.previous-message-sender {
|
||||
font-weight:bold;
|
||||
margin-right:10px;
|
||||
margin-left:-10px;
|
||||
color:#ED3618;
|
||||
|
||||
&:after {
|
||||
content:':'
|
||||
}
|
||||
}
|
||||
.previous-messages-scroller {
|
||||
height:250px;
|
||||
position:relative;
|
||||
display:block;
|
||||
overflow:auto;
|
||||
}
|
||||
|
||||
.previous-messages {
|
||||
padding:10px;
|
||||
color:white;
|
||||
}
|
||||
|
||||
.previous-message {
|
||||
margin:5px 0;
|
||||
}
|
||||
|
||||
.previous-message-text {
|
||||
line-height:18px;
|
||||
}
|
||||
|
||||
.previous-message-timestamp {
|
||||
margin-top:4px;
|
||||
color:#AAA;
|
||||
display:block;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
.text-message-scroller {
|
||||
width: 100%;
|
||||
height: 4em;
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
.text-message-box {
|
||||
|
||||
}
|
||||
|
||||
#new-text-message {
|
||||
width:100%;
|
||||
height:40px;
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ class ApiController < ApplicationController
|
|||
end
|
||||
rescue_from 'JamRuby::JamArgumentError' do |exception|
|
||||
@exception = exception
|
||||
render "errors/jam_argument_error", :status => 400
|
||||
render "errors/jam_argument_error", :status => 422
|
||||
end
|
||||
rescue_from 'JamRuby::PermissionError' do |exception|
|
||||
@exception = exception
|
||||
|
|
|
|||
|
|
@ -302,7 +302,24 @@ class ApiUsersController < ApiController
|
|||
|
||||
###################### NOTIFICATIONS ####################
|
||||
def notification_index
|
||||
@notifications = @user.notifications
|
||||
if params[:type] == 'TEXT_MESSAGE'
|
||||
# you can ask for just text_message notifications
|
||||
|
||||
raise JamArgumentError.new('can\'t be blank', 'receiver') if params[:receiver].blank?
|
||||
raise JamArgumentError.new('can\'t be blank', 'limit') if params[:limit].blank?
|
||||
raise JamArgumentError.new('can\'t be blank', 'offset') if params[:offset].blank?
|
||||
|
||||
receiver_id = params[:receiver]
|
||||
limit = params[:limit]
|
||||
limit = limit.to_i
|
||||
offset = params[:offset]
|
||||
offset = offset.to_i
|
||||
@notifications = Notification.where(description: 'TEXT_MESSAGE').where('(source_user_id = (?) AND target_user_id = (?)) OR (source_user_id = (?) AND target_user_id = (?))', @user.id, receiver_id, receiver_id, @user.id).offset(offset).limit(limit).order('created_at DESC')
|
||||
else
|
||||
# you can ask for all notifications
|
||||
@notifications = @user.notifications
|
||||
end
|
||||
|
||||
respond_with @notifications, responder: ApiResponder, :status => 200
|
||||
end
|
||||
|
||||
|
|
@ -311,6 +328,12 @@ class ApiUsersController < ApiController
|
|||
respond_with responder: ApiResponder, :status => 204
|
||||
end
|
||||
|
||||
def notification_create
|
||||
@notification = Notification.send_text_message(params[:message], current_user, User.find_by_id(params[:receiver]))
|
||||
respond_with_model(@notification, new: true)
|
||||
end
|
||||
|
||||
|
||||
##################### BAND INVITATIONS ##################
|
||||
def band_invitation_index
|
||||
@invitations = @user.received_band_invitations
|
||||
|
|
|
|||
|
|
@ -28,11 +28,7 @@ class ClientsController < ApplicationController
|
|||
gon.use_cached_session_scores = Rails.application.config.use_cached_session_scores
|
||||
gon.allow_both_find_algos = Rails.application.config.allow_both_find_algos
|
||||
|
||||
if current_user
|
||||
render :layout => 'client'
|
||||
else
|
||||
redirect_to root_url
|
||||
end
|
||||
render :layout => 'client'
|
||||
end
|
||||
|
||||
AUTHED = %W{friend}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,16 @@ class SessionsController < ApplicationController
|
|||
|
||||
def new
|
||||
@login_error = false
|
||||
@sso = params[:sso]
|
||||
@send_back_to = request.headers['REFERER']
|
||||
params[:send_back_to] = @send_back_to
|
||||
|
||||
if current_user
|
||||
# send them on their way
|
||||
complete_sign_in(current_user)
|
||||
return
|
||||
end
|
||||
|
||||
render :layout => "landing"
|
||||
end
|
||||
|
||||
|
|
@ -13,6 +23,8 @@ class SessionsController < ApplicationController
|
|||
|
||||
if user.nil?
|
||||
@login_error = true
|
||||
@sso = params[:sso]
|
||||
@send_back_to = params[:send_back_to]
|
||||
render 'new', :layout => "landing"
|
||||
else
|
||||
|
||||
|
|
@ -133,16 +145,30 @@ class SessionsController < ApplicationController
|
|||
render 'oauth_complete', :layout => "landing"
|
||||
end
|
||||
|
||||
def redirect_after_signin(default)
|
||||
redirect_to(params['redirect-to'].blank? ? default : params['redirect-to'])
|
||||
end
|
||||
|
||||
def redirect_to_forums_after_signin
|
||||
redirect_to("#{Rails.application.config.vanilla_login_url}?client_id=#{Rails.application.config.vanilla_client_id}&Target=#{ERB::Util.url_encode(params[:send_back_to].blank? ? '/' : params[:send_back_to])}")
|
||||
end
|
||||
|
||||
def redirect_to_support_after_signin(user)
|
||||
# generate multipass token and sign it
|
||||
multipass = DeskMultipass.new(user)
|
||||
callback_url = Rails.application.config.multipass_callback_url
|
||||
redirect_to "#{callback_url}?multipass=#{multipass.token}&signature=#{multipass.signature}"
|
||||
end
|
||||
|
||||
def complete_sign_in(user)
|
||||
sign_in user
|
||||
|
||||
if !params[:sso].nil? && params[:sso] == "desk"
|
||||
# generate multipass token and sign it
|
||||
multipass = DeskMultipass.new(user)
|
||||
callback_url = SampleApp::Application.config.multipass_callback_url
|
||||
redirect_to "#{callback_url}?multipass=#{multipass.token}&signature=#{multipass.signature}"
|
||||
if params[:sso] == "desk"
|
||||
redirect_to_support_after_signin(user)
|
||||
elsif params[:sso] == 'forums'
|
||||
redirect_to_forums_after_signin
|
||||
else
|
||||
redirect_back_or client_url
|
||||
redirect_after_signin(client_path)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ class UsersController < ApplicationController
|
|||
|
||||
@fb_signup = load_facebook_signup(params)
|
||||
|
||||
# check if the email specified by @fb_signup already exists in the databse--if so, log them in and redirect
|
||||
# check if the email specified by @fb_signup already exists in the database--if so, log them in and redirect
|
||||
if @fb_signup && @fb_signup.email
|
||||
user = User.find_by_email_and_email_confirmed(@fb_signup, true)
|
||||
if user
|
||||
|
|
@ -117,7 +117,7 @@ class UsersController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
# check if the uid specified by @fb_signup already exists in the databse--if so, log them in and redirect
|
||||
# check if the uid specified by @fb_signup already exists in the database--if so, log them in and redirect
|
||||
if @fb_signup && @fb_signup.uid
|
||||
user_authorization = UserAuthorization.find_by_uid_and_provider(@fb_signup.uid, 'facebook')
|
||||
# update user_authorization for user because this is fresher
|
||||
|
|
@ -199,10 +199,10 @@ class UsersController < ApplicationController
|
|||
|
||||
@slides = [
|
||||
Slide.new("JamKazam Overview", "web/carousel_musicians.jpg", "http://www.youtube.com/embed/ylYcvTY9CVo?autoplay=1"),
|
||||
Slide.new("Getting Started", "web/carousel_fans.jpg", "http://www.youtube.com/embed/ylYcvTY9CVo?autoplay=1"),
|
||||
Slide.new("Getting Started", "web/carousel_fans.jpg", "http://www.youtube.com/embed/VexH4834o9I?autoplay=1"),
|
||||
Slide.new("Playing in a Session", "web/carousel_bands.jpg", "http://www.youtube.com/embed/ylYcvTY9CVo?autoplay=1"),
|
||||
Slide.new("JamKazam Overview", "web/carousel_musicians.jpg", "http://www.youtube.com/embed/ylYcvTY9CVo?autoplay=1"),
|
||||
Slide.new("Getting Started", "web/carousel_fans.jpg", "http://www.youtube.com/embed/ylYcvTY9CVo?autoplay=1"),
|
||||
Slide.new("Getting Started", "web/carousel_fans.jpg", "http://www.youtube.com/embed/VexH4834o9I?autoplay=1"),
|
||||
Slide.new("Playing in a Session", "web/carousel_bands.jpg", "http://www.youtube.com/embed/ylYcvTY9CVo?autoplay=1")
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
require 'base64'
|
||||
require 'js_connect'
|
||||
|
||||
class VanillaForumsController < ApplicationController
|
||||
|
||||
@@log = Logging.logger[VanillaForumsController]
|
||||
|
||||
# displays the embedded forum
|
||||
# see http://vanillaforums.com/blog/jsconnect-technical-documentation-for-embedded-sso/
|
||||
def show
|
||||
|
||||
user = {name: '', photourl: ''}
|
||||
if current_user
|
||||
user = {email: current_user.email, name: current_user.username,
|
||||
photourl: current_user.profile_pic,
|
||||
uniqueid: current_user.username}
|
||||
end
|
||||
user.merge!({client_id: Rails.application.config.vanilla_client_id})
|
||||
|
||||
# json encode the user
|
||||
json = ActiveSupport::JSON.encode(user);
|
||||
# base 64 encode the user json
|
||||
signature_string = Base64.strict_encode64(json)
|
||||
# Sign the signature string with current timestamp using hmac sha1
|
||||
signature = Digest::HMAC.hexdigest(signature_string + ' ' +
|
||||
Time.now.to_i.to_s, Rails.application.config.vanilla_secret, Digest::SHA1)
|
||||
# build the final sso string
|
||||
@vanilla_sso = "#{signature_string} #{signature} #{Time.now.to_i} hmacsha1"
|
||||
|
||||
end
|
||||
|
||||
# callback for vanilla authentication
|
||||
# see http://vanillaforums.com/blog/jsconnect-technical-documentation
|
||||
# ruby jsconnect client library: https://github.com/vanillaforums/jsConnectRuby
|
||||
def authenticate
|
||||
|
||||
user = {}
|
||||
if current_user
|
||||
|
||||
user = {'email' => current_user.email, 'name' => current_user.name,
|
||||
'photourl' => current_user.resolved_photo_url,
|
||||
'uniqueid' => current_user.id}
|
||||
|
||||
@@log.debug("user is logged in: #{user}")
|
||||
else
|
||||
@@log.debug("user is not logged in")
|
||||
end
|
||||
|
||||
|
||||
render :json => JsConnect::getJsConnectString(user, request,
|
||||
Rails.application.config.vanilla_client_id, Rails.application.config.vanilla_secret)
|
||||
|
||||
end
|
||||
|
||||
# only for testing; routes are conditionally based on test ENV
|
||||
def fake_root
|
||||
render layout: 'web'
|
||||
end
|
||||
# only for testing; routes are conditionally based on test ENV
|
||||
def fake_jsconnect
|
||||
render layout: 'web'
|
||||
end
|
||||
end
|
||||
|
|
@ -8,15 +8,20 @@ module SessionsHelper
|
|||
def set_remember_token(user)
|
||||
if @session_only_cookie
|
||||
cookies.delete(:remember_token)
|
||||
cookies[:remember_token] = user.remember_token
|
||||
cookies[:remember_token] = {
|
||||
value: user.remember_token,
|
||||
domain: Rails.application.config.session_cookie_domain
|
||||
}
|
||||
else
|
||||
cookies[:remember_token] = {
|
||||
:value => user.remember_token,
|
||||
:expires => 20.years.from_now.utc
|
||||
value: user.remember_token,
|
||||
expires: 20.years.from_now.utc,
|
||||
domain: Rails.application.config.session_cookie_domain
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def signed_in?
|
||||
!current_user.nil?
|
||||
end
|
||||
|
|
@ -49,7 +54,7 @@ module SessionsHelper
|
|||
|
||||
def sign_out
|
||||
current_user = nil
|
||||
cookies.delete(:remember_token)
|
||||
cookies.delete(:remember_token, domain: Rails.application.config.session_cookie_domain)
|
||||
end
|
||||
|
||||
def redirect_back_or(default)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
object @notification
|
||||
|
||||
attributes :id
|
||||
|
|
@ -1,6 +1,14 @@
|
|||
collection @notifications
|
||||
|
||||
attributes :description, :source_user_id, :target_user_id, :session_id, :recording_id, :invitation_id, :join_request_id, :friend_request_id, :band_id, :band_invitation_id, :formatted_msg, :created_at
|
||||
attributes :description, :source_user_id, :target_user_id, :session_id, :recording_id, :invitation_id, :join_request_id, :friend_request_id, :band_id, :band_invitation_id, :formatted_msg, :message, :created_at
|
||||
|
||||
node :source_user do |n|
|
||||
source_user_data = {}
|
||||
if n.source_user
|
||||
source_user_data[:name] = n.source_user.name
|
||||
end
|
||||
source_user_data
|
||||
end
|
||||
|
||||
node :notification_id do |n|
|
||||
n.id
|
||||
|
|
|
|||
|
|
@ -93,20 +93,8 @@
|
|||
<div id="band-setup-step-2" class="content-wrapper" style="padding:10px 35px 10px 35px; display:none;">
|
||||
<br/>
|
||||
<h2>Step 2: Add Band Members</h2><br/>
|
||||
<div class="left w70">If your bandmates are already on JamKazam, start typing their names in the box<br/> below, or click the Choose Friends button to select them.</div>
|
||||
<div class="right" layout-link="select-friends">
|
||||
<a href="#" id="btn-band-choose-friends" class="button-grey right">CHOOSE FRIENDS</a>
|
||||
</div>
|
||||
<br clear="all" />
|
||||
<br />
|
||||
|
||||
<div class="friendbox">
|
||||
<div id="selected-band-invitees"></div>
|
||||
<input id="band-invitee-input" type="text" placeholder="Looking up friends..." width="150px" />
|
||||
</div>
|
||||
<br/><br/>
|
||||
If your bandmates are not on JamKazam yet, use any of the options below to invite them to join the service.<br/><br/>
|
||||
|
||||
<div id="band-setup-invite-musicians"></div>
|
||||
If your bandmates are not on JamKazam yet, use any of the options below to invite them to join the service.<br/><br/>
|
||||
<div class="left mr20">
|
||||
<div class="left">
|
||||
<a class="btn-email-invitation">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
<!-- footer links -->
|
||||
<div id="footer-links">
|
||||
<%= link_to "about", corp_about_path , :rel=>"external" %> | <%= link_to "news", corp_news_path , :rel=>"external" %> | <%= link_to "media", corp_media_center_path , :rel=>"external" %> | <%= link_to "contact", corp_contact_path , :rel=>"external" %> | <%= link_to "privacy", corp_privacy_path, :rel=>"external" %> | <%= link_to "terms of service", corp_terms_path , :rel=>"external" %> | <%= link_to "help", corp_help_path , :rel=>"external" %>
|
||||
<%= link_to "about", corp_about_path , :rel=>"external" %> | <%= link_to "news", corp_news_path , :rel=>"external" %> | <%= link_to "media", corp_media_center_path , :rel=>"external" %> | <%= link_to "contact", corp_contact_path , :rel=>"external" %> | <%= link_to "privacy", corp_privacy_path, :rel=>"external" %> | <%= link_to "terms of service", corp_terms_path , :rel=>"external" %> | <%= link_to "community forum", Rails.application.config.vanilla_url, :rel=>"external" %> | <%= link_to "help", corp_help_path , :rel=>"external" %>
|
||||
</div>
|
||||
|
||||
<%= render "clients/recordingManager" %>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div id="band-hover" class="hidden bubble">
|
||||
<div id="band-hover" class="hidden bubble band-bubble">
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div id="fan-hover" class="hidden bubble">
|
||||
<div id="fan-hover" class="hidden bubble fan-bubble">
|
||||
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div id="musician-hover" class="hidden bubble">
|
||||
<div id="musician-hover" class="hidden bubble musician-bubble">
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -146,6 +146,23 @@
|
|||
});
|
||||
}
|
||||
|
||||
function messageMusician(userId) {
|
||||
if(JK.TextMessageDialogInstance) {
|
||||
JK.app.layout.showDialog('text-message', {d1: userId})
|
||||
}
|
||||
else {
|
||||
var goto = $('<span>We are sorry, but you can\'t message from this page.</span>');
|
||||
JK.app.notify(
|
||||
{
|
||||
title: "Unable to Message From Here",
|
||||
text: goto
|
||||
},
|
||||
{ no_cancel: true });
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function adjustMusicianFollowingCount(value) {
|
||||
$("#spnFollowCount", "#musician-hover").html(parseInt($("#spnFollowCount", "#musician-hover").html()) + value);
|
||||
}
|
||||
|
|
@ -200,6 +217,7 @@
|
|||
<div class="left" style="display:none;"><a id="btnLike" onclick="addLike('{userId}');" class="button-orange">LIKE</a></div>
|
||||
<div class="left"><a id="btnFriend" onclick="{friendAction}('{userId}');" class="button-orange">CONNECT</a></div>
|
||||
<div class="left"><a id="btnFollow" onclick="{followAction}('{userId}');" class="button-orange">FOLLOW</a></div>
|
||||
<div class="left"><a id="btnMessage" onclick="messageMusician('{userId}');" class="button-orange">MESSAGE</a></div>
|
||||
</div>
|
||||
<br /><br />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,16 +17,14 @@
|
|||
<div class="right" layout-link="select-friends">
|
||||
<a href="#" class="btn-choose-friends button-grey" id="{choose_friends_id}">CHOOSE FRIENDS</a>
|
||||
</div>
|
||||
<div style="margin-right:140px;">
|
||||
Start typing friends'' names or:
|
||||
</div>
|
||||
{instructions}
|
||||
<div class="clearall"></div>
|
||||
</div>
|
||||
<br />
|
||||
<!-- friend invitation box -->
|
||||
<div class="friendbox">
|
||||
<div class="selected-friends" id="{selected_friends_id}"></div>
|
||||
<input id="friend-input" type="text" placeholder="Looking up friends..." />
|
||||
<input id="{friend_input}" type="text" placeholder="Looking up friends..." />
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<%= select_tag('musician_query_distance', options_for_select(Search::M_DISTANCE_OPTS, Search::M_MILES_DEFAULT)) %>
|
||||
<% end -%>
|
||||
<%= content_tag(:div, :class => 'filter-element') do -%>
|
||||
miles of <%= content_tag(:span, current_user.current_city(request.remote_ip), :id => 'musician-filter-city') %>
|
||||
miles of <%= content_tag(:span, current_user ? current_user.current_city(request.remote_ip) : '', :id => 'musician-filter-city') %>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
<%= content_tag(:div,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,10 @@
|
|||
<%= render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_MUSICIAN}) %>
|
||||
<%= content_tag(:div, :class => 'filter-body') do %>
|
||||
<%= content_tag(:div, :class => 'content-body-scroller') do -%>
|
||||
<%= content_tag(:div, content_tag(:div, '', :id => 'musician-filter-results', :class => 'filter-results'), :class => 'content-wrapper musician-wrapper') %>
|
||||
<%= content_tag(:div, :class => 'content-wrapper musician-wrapper') do -%>
|
||||
<%= content_tag(:div, '', :id => 'musician-filter-results', :class => 'filter-results') %>
|
||||
<%= content_tag(:div, 'No more results.', :class => 'end-of-list', :id => 'end-of-musician-list') %>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
<% end -%>
|
||||
|
|
@ -63,10 +66,11 @@
|
|||
|
||||
<script type="text/template" id="template-musician-action-btns">
|
||||
<a href="{profile_url}" class="button-orange smallbutton">PROFILE</a>
|
||||
<% if current_user.musician? %>
|
||||
<% if current_user && current_user.musician? %>
|
||||
<a href="#" class="{friend_class} smallbutton search-m-friend">{friend_caption}</a>
|
||||
<% end %>
|
||||
<a href="#" class="{follow_class} smallbutton search-m-follow">{follow_caption}</a>
|
||||
<a href="#" class="{message_class} smallbutton search-m-message">{message_caption}</a>
|
||||
<!--<a href="#" class="{button_message} smallbutton search-m-like">MESSAGE</a>-->
|
||||
<div class="clearall"></div>
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
<div class="right">
|
||||
<a id="btn-add-friend" class="button-orange">ADD FRIEND</a>
|
||||
<a id="btn-follow-user" class="button-orange">FOLLOW</a>
|
||||
<a id="btn-message-user" class="button-orange">MESSAGE</a>
|
||||
<%= link_to("EDIT PROFILE", '/client#/account/profile', :id => "btn-profile-edit", :class => "button-orange") %>
|
||||
</div>
|
||||
<br clear="all" /><br />
|
||||
|
|
|
|||
|
|
@ -217,6 +217,7 @@
|
|||
</li>
|
||||
</script>
|
||||
|
||||
|
||||
<!-- Chat panel template -->
|
||||
<script type="text/template" id="template-chat-panel">
|
||||
<li>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
.dialog.textMessage-overlay.ftue-overlay.tall{ layout: 'dialog', 'layout-id' => 'text-message', id: 'text-message-dialog'}
|
||||
.content-head
|
||||
= image_tag "content/icon_comment.png", {:width => 12, :height => 12, :class => 'content-icon' }
|
||||
%h1
|
||||
= 'conversation with'
|
||||
%span.receiver-name
|
||||
.dialog-inner
|
||||
.previous-messages-scroller
|
||||
.previous-messages
|
||||
.text-message-scroller
|
||||
%form.text-message-box
|
||||
%textarea{ name: 'new-text-message', id: 'new-text-message' }
|
||||
.left
|
||||
%span.small.offline-tip An email will be sent if recipient is offline
|
||||
.right
|
||||
%a.button-grey.btn-close-dialog{href:'#', 'layout-action' => 'close'} CLOSE
|
||||
%a.button-orange.btn-send-text-message{href:'#'} SEND
|
||||
|
||||
%script{type: 'text/template', id: 'template-previous-message'}
|
||||
.previous-message
|
||||
%span.previous-message-sender= '{{data.sender}}'
|
||||
%span.previous-message-text= '{{data.msg}}'
|
||||
%time.previous-message-timestamp.timeago{datetime: '{{data.sent}}'}= '{{data.sent}}'
|
||||
|
|
@ -55,7 +55,7 @@
|
|||
<%= select_tag("#{filter_label}_query_distance", options_for_select(Search::DISTANCE_OPTS, default_distance), {:class => 'easydropdown'}) %>
|
||||
<% end -%>
|
||||
<%= content_tag(:div, :class => 'filter-element desc') do -%>
|
||||
miles of <%= content_tag(:span, current_user.current_city(request.remote_ip), :id => "#{filter_label}-filter-city") %>
|
||||
miles of <%= content_tag(:span, current_user ? current_user.current_city(request.remote_ip) : '', :id => "#{filter_label}-filter-city") %>
|
||||
<% end -%>
|
||||
<!-- @end distance filter -->
|
||||
<% end %>
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
<%= render "recordingFinishedDialog" %>
|
||||
<%= render "localRecordingsDialog" %>
|
||||
<%= render "showServerErrorDialog" %>
|
||||
<%= render "textMessageDialog" %>
|
||||
<%= render "notify" %>
|
||||
<%= render "client_update" %>
|
||||
<%= render "banner" %>
|
||||
|
|
@ -107,6 +108,11 @@
|
|||
JK.currentUserName = null;
|
||||
JK.currentUserMusician = null;
|
||||
JK.currentUserAdmin = false;
|
||||
|
||||
// you need to be logged in to use this part of the interface.
|
||||
// save original URL, and redirect to the home page
|
||||
logger.debug("redirecting back to / because not logged in")
|
||||
window.location.href = '/?redirect-to=' + encodeURIComponent(JK.locationPath());
|
||||
<% end %>
|
||||
|
||||
// Some things can't be initialized until we're connected. Put them here.
|
||||
|
|
@ -123,6 +129,10 @@
|
|||
var invitationDialog = new JK.InvitationDialog(JK.app);
|
||||
invitationDialog.initialize(facebookHelper);
|
||||
|
||||
var textMessageDialog = new JK.TextMessageDialog(JK.app);
|
||||
JK.TextMessageDialogInstance = textMessageDialog;
|
||||
textMessageDialog.initialize();
|
||||
|
||||
var localRecordingsDialog = new JK.LocalRecordingsDialog(JK.app);
|
||||
localRecordingsDialog.initialize();
|
||||
|
||||
|
|
@ -132,9 +142,6 @@
|
|||
var friendSelectorDialog = new JK.FriendSelectorDialog(JK.app);
|
||||
friendSelectorDialog.initialize();
|
||||
|
||||
var inviteMusiciansUtil = new JK.InviteMusiciansUtil(JK.app);
|
||||
inviteMusiciansUtil.initialize(friendSelectorDialog);
|
||||
|
||||
var userDropdown = new JK.UserDropdown(JK.app);
|
||||
JK.UserDropdown = userDropdown;
|
||||
userDropdown.initialize(invitationDialog);
|
||||
|
|
@ -144,13 +151,13 @@
|
|||
header.initialize();
|
||||
|
||||
var sidebar = new JK.Sidebar(JK.app);
|
||||
sidebar.initialize(invitationDialog);
|
||||
sidebar.initialize(invitationDialog, textMessageDialog);
|
||||
|
||||
var homeScreen = new JK.HomeScreen(JK.app);
|
||||
homeScreen.initialize();
|
||||
|
||||
var profileScreen = new JK.ProfileScreen(JK.app);
|
||||
profileScreen.initialize();
|
||||
profileScreen.initialize(textMessageDialog);
|
||||
|
||||
var bandProfileScreen = new JK.BandProfileScreen(JK.app);
|
||||
bandProfileScreen.initialize();
|
||||
|
|
@ -177,11 +184,15 @@
|
|||
JK.GenreSelectorHelper.initialize();
|
||||
JK.Banner.initialize();
|
||||
|
||||
var inviteMusiciansUtil1 = new JK.InviteMusiciansUtil(JK.app);
|
||||
inviteMusiciansUtil1.initialize(friendSelectorDialog);
|
||||
var createSessionScreen = new JK.CreateSessionScreen(JK.app);
|
||||
createSessionScreen.initialize(invitationDialog, inviteMusiciansUtil);
|
||||
createSessionScreen.initialize(invitationDialog, inviteMusiciansUtil1);
|
||||
|
||||
var inviteMusiciansUtil2 = new JK.InviteMusiciansUtil(JK.app);
|
||||
inviteMusiciansUtil2.initialize(friendSelectorDialog);
|
||||
var bandSetupScreen = new JK.BandSetupScreen(JK.app);
|
||||
bandSetupScreen.initialize(invitationDialog, friendSelectorDialog);
|
||||
bandSetupScreen.initialize(invitationDialog, inviteMusiciansUtil2);
|
||||
|
||||
var bandSetupPhotoScreen = new JK.BandSetupPhotoScreen(JK.app);
|
||||
bandSetupPhotoScreen.initialize();
|
||||
|
|
@ -197,13 +208,15 @@
|
|||
findSessionScreen.initialize(sessionLatency);
|
||||
|
||||
var findMusicianScreen = new JK.FindMusicianScreen(JK.app);
|
||||
findMusicianScreen.initialize();
|
||||
findMusicianScreen.initialize(textMessageDialog);
|
||||
|
||||
var findBandScreen = new JK.FindBandScreen(JK.app);
|
||||
findBandScreen.initialize();
|
||||
|
||||
var inviteMusiciansUtil3 = new JK.InviteMusiciansUtil(JK.app);
|
||||
inviteMusiciansUtil3.initialize(friendSelectorDialog);
|
||||
var sessionScreen = new JK.SessionScreen(JK.app);
|
||||
sessionScreen.initialize(localRecordingsDialog, recordingFinishedDialog, inviteMusiciansUtil);
|
||||
sessionScreen.initialize(localRecordingsDialog, recordingFinishedDialog, inviteMusiciansUtil3);
|
||||
|
||||
var sessionSettingsDialog = new JK.SessionSettingsDialog(JK.app, sessionScreen);
|
||||
sessionSettingsDialog.initialize();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
object @exception
|
||||
|
||||
attributes :message
|
||||
node do |exception|
|
||||
field = exception.field ? exception.field : 'unknown'
|
||||
errors = {}
|
||||
errors[field] = [exception.field_message]
|
||||
{
|
||||
errors: errors
|
||||
}
|
||||
end
|
||||
|
||||
node "type" do
|
||||
"ArgumentError"
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@
|
|||
<div id="copyright">Copyright © <%= Time.now.year %> JamKazam, Inc. All Rights Reserved</div>
|
||||
|
||||
<!-- footer links -->
|
||||
<div id="footer-links"><%= link_to "about", corp_about_path %> | <%= link_to "news", corp_news_path %> | <%= link_to "media", corp_media_center_path %> | <%= link_to "contact", corp_contact_path %> | <%= link_to "privacy", corp_privacy_path %> | <%= link_to "terms of service", corp_terms_path %> | <%= link_to "help", corp_help_path %></div>
|
||||
<div id="footer-links"><%= link_to "about", corp_about_path %> | <%= link_to "news", corp_news_path %> | <%= link_to "media", corp_media_center_path %> | <%= link_to "contact", corp_contact_path %> | <%= link_to "privacy", corp_privacy_path %> | <%= link_to "terms of service", corp_terms_path %> | <%= link_to "community forum", Rails.application.config.vanilla_url, :rel=>"external" %> | <%= link_to "help", corp_help_path %></div>
|
||||
|
||||
<div id="version"><%= version %></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,8 +16,9 @@
|
|||
Enter your email address and password:
|
||||
|
||||
<div>
|
||||
<%= form_for(:session, url: sessions_path) do |f| %>
|
||||
<input type="hidden" name="sso" value="<%= params[:sso] %>">
|
||||
<%= form_for(:session, url: signin_path + (request.query_string.blank? ? '' : '?' + request.query_string)) do |f| %>
|
||||
<input type="hidden" name="sso" value="<%= @sso %>">
|
||||
<input type="hidden" name="send_back_to" value="<%= @send_back_to %>">
|
||||
<fieldset name="text-input" class="<%= 'login-error' if @login_error %>">
|
||||
|
||||
<div class="field email">
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
</ul>
|
||||
</li>
|
||||
<li class="download-app"><%= link_to "Download App", downloads_path, :rel => "external" %></li>
|
||||
<li class="community-forum"><%= link_to "Community Forum", Rails.application.config.vanilla_url, :rel => "external" %></li>
|
||||
<li class="get-help"><%= link_to "Get Help", 'https://jamkazam.desk.com/', :rel => "external" %></li>
|
||||
<li class="sign-out"><%= link_to "Sign Out", signout_path, method: "delete" %></li>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
%h1 welcome to fake login page
|
||||
|
|
@ -0,0 +1 @@
|
|||
%h1 welcome to fake vanilla forums
|
||||
|
|
@ -218,5 +218,18 @@ if defined?(Bundler)
|
|||
# should we use the new FindSessions API that has server-side scores
|
||||
config.use_cached_session_scores = true
|
||||
config.allow_both_find_algos = false
|
||||
|
||||
config.session_cookie_domain = nil
|
||||
|
||||
# these are production values. we should have a test server, but would require us to set one up
|
||||
# we do have some 'fake pages' in the vanilla_forums_controller.rb to get close
|
||||
config.vanilla_client_id = 'www'
|
||||
config.vanilla_secret = 'bibbitybobbityslipperyslopes'
|
||||
config.vanilla_url = 'http://forums.jamkazam.com'
|
||||
config.vanilla_login_url = 'http://forums.jamkazam.com/entry/jsconnect'
|
||||
|
||||
# we have to do this for a while until all www.jamkazam.com cookies are gone,
|
||||
# and only .jamkazam.com cookies are around.. 2016?
|
||||
config.middleware.insert_before "ActionDispatch::Cookies", "Middlewares::ClearDuplicatedSession"
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ SampleApp::Application.configure do
|
|||
# For testing omniauth
|
||||
OmniAuth.config.test_mode = true
|
||||
|
||||
config.websocket_gateway_enable = true
|
||||
config.websocket_gateway_enable = false
|
||||
config.websocket_gateway_port = 6769
|
||||
config.websocket_gateway_uri = "ws://localhost:#{config.websocket_gateway_port}/websocket"
|
||||
|
||||
|
|
@ -69,5 +69,10 @@ SampleApp::Application.configure do
|
|||
config.use_promos_on_homepage = false
|
||||
|
||||
config.use_cached_session_scores = true
|
||||
|
||||
config.session_cookie_domain = nil
|
||||
|
||||
config.vanilla_url = '/forums'
|
||||
config.vanilla_login_url = '/forums/entry/jsconnect'
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
unless $rails_rake_task
|
||||
|
||||
JamWebEventMachine.start
|
||||
|
|
@ -14,5 +13,6 @@ unless $rails_rake_task
|
|||
:rabbitmq_host => APP_CONFIG.rabbitmq_host,
|
||||
:rabbitmq_port => APP_CONFIG.rabbitmq_port)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ SampleApp::Application.routes.draw do
|
|||
match '/congratulations_fan', to: 'users#congratulations_fan'
|
||||
match '/downloads', to: 'users#downloads'
|
||||
|
||||
match '/signin', to: 'sessions#new'
|
||||
match '/signin', to: 'sessions#new', via: :get
|
||||
match '/signin', to: 'sessions#create', via: :post
|
||||
match '/signout', to: 'sessions#destroy', via: :delete
|
||||
|
||||
# oauth
|
||||
|
|
@ -84,8 +85,16 @@ SampleApp::Application.routes.draw do
|
|||
|
||||
if Rails.env == "test"
|
||||
match '/test_connection', to: 'sessions#connection_state', :as => :connection_state
|
||||
|
||||
# vanilla forums 'fake methods'
|
||||
match '/forums', to: 'vanilla_forums#fake_root'
|
||||
match '/forums/entry/jsconnect', to: 'vanilla_forums#fake_jsconnect'
|
||||
end
|
||||
|
||||
# vanilla forums sso
|
||||
match '/forums/sso', to: 'vanilla_forums#authenticate'
|
||||
|
||||
|
||||
scope '/corp' do
|
||||
# about routes
|
||||
match '/about', to: 'corps#about', as: 'corp_about'
|
||||
|
|
@ -219,6 +228,7 @@ SampleApp::Application.routes.draw do
|
|||
# notifications
|
||||
match '/users/:id/notifications' => 'api_users#notification_index', :via => :get
|
||||
match '/users/:id/notifications/:notification_id' => 'api_users#notification_destroy', :via => :delete
|
||||
match '/users/:id/notifications' => 'api_users#notification_create', :via => :post
|
||||
|
||||
# user band invitations
|
||||
match '/users/:id/band_invitations' => 'api_users#band_invitation_index', :via => :get
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
# This module contains the client code for Vanilla jsConnect single sign on
|
||||
# Author:: Todd Burry (mailto:todd@vanillaforums.com)
|
||||
# Version:: 1.0b
|
||||
# Copyright:: Copyright 2008, 2009 Vanilla Forums Inc.
|
||||
# License http://www.opensource.org/licenses/gpl-2.0.php GPLv2
|
||||
|
||||
|
||||
module JsConnect
|
||||
|
||||
@@log = Logging.logger[JsConnect]
|
||||
|
||||
def JsConnect.error(code, message)
|
||||
return {"error" => code, "message" => message}
|
||||
end
|
||||
|
||||
def JsConnect.getJsConnectString(user, request = {}, client_id = "", secret = "", secure = true)
|
||||
error = nil
|
||||
|
||||
timestamp = request["timestamp"].to_i
|
||||
current_timestamp = JsConnect.timestamp
|
||||
|
||||
if secure
|
||||
# Make sure the request coming in is signed properly
|
||||
|
||||
if !request['client_id']
|
||||
error = JsConnect.error('invalid_request', 'The client_id parameter is missing.')
|
||||
elsif request['client_id'] != client_id
|
||||
error = JsConnect.error('invalid_client', "Unknown client #{request['client_id']}.")
|
||||
elsif request['timestamp'].nil? and request['signature'].nil?
|
||||
@@log.debug("no timestamp right? #{request['timestamp']}, #{request['signature']}")
|
||||
if user and !user.empty?
|
||||
error = {'name' => user['name'], 'photourl' => user['photourl']}
|
||||
else
|
||||
error = {'name' => '', 'photourl' => ''}
|
||||
end
|
||||
elsif request['timestamp'].nil?
|
||||
error = JsConnect.error('invalid_request', 'The timestamp is missing or invalid.')
|
||||
elsif !request['signature']
|
||||
error = JsConnect.error('invalid_request', 'The signature is missing.')
|
||||
elsif (current_timestamp - timestamp).abs > 30 * 60
|
||||
error = JsConnect.error('invalid_request', 'The timestamp is invalid.')
|
||||
else
|
||||
# Make sure the timestamp's signature checks out.
|
||||
timestamp_sig = Digest::MD5.hexdigest(timestamp.to_s + secret)
|
||||
if timestamp_sig != request['signature']
|
||||
error = JsConnect.error('access_denied', 'Signature invalid.')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if error
|
||||
@@log.debug("not valid request: #{error}")
|
||||
result = error
|
||||
elsif user and !user.empty?
|
||||
result = user.clone
|
||||
@@log.debug("logging in: #{error}")
|
||||
JsConnect.signJsConnect(result, client_id, secret, true)
|
||||
else
|
||||
@@log.debug("anonymous")
|
||||
result = {"name" => "", "photourl" => ""}
|
||||
end
|
||||
|
||||
json = ActiveSupport::JSON.encode(result);
|
||||
if request["callback"]
|
||||
return "#{request["callback"]}(#{json});"
|
||||
else
|
||||
return json
|
||||
end
|
||||
end
|
||||
|
||||
def JsConnect.signJsConnect(data, client_id, secret, set_data = false)
|
||||
# Build the signature string. This is essentially a querystring representation of data, sorted by key
|
||||
keys = data.keys.sort { |a,b| a.downcase <=> b.downcase }
|
||||
|
||||
sig_str = ""
|
||||
|
||||
keys.each do |key|
|
||||
if sig_str.length > 0
|
||||
sig_str += "&"
|
||||
end
|
||||
|
||||
value = data[key]
|
||||
@@log.debug("key #{key}, value #{value}")
|
||||
sig_str += CGI.escape(key) + "=" + CGI.escape(value)
|
||||
end
|
||||
|
||||
signature = Digest::MD5.hexdigest(sig_str + secret);
|
||||
|
||||
if set_data
|
||||
data["clientid"] = client_id
|
||||
data["signature"] = signature
|
||||
end
|
||||
return signature
|
||||
end
|
||||
|
||||
def JsConnect.timestamp
|
||||
return Time.now.to_i
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
# http://astashov.github.io/2011/02/26/conflict-of-session-cookies-with-different-domains-in-rails-3.html
|
||||
|
||||
# We had to do this when we changed from www.jamkazam.com to .jamkazam.com as the cookie served out
|
||||
|
||||
module Middlewares
|
||||
class ClearDuplicatedSession
|
||||
|
||||
@@log = Logging.logger[ClearDuplicatedSession]
|
||||
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
status, headers, body = @app.call(env)
|
||||
|
||||
headers.each do|k,v|
|
||||
if k == 'Set-Cookie' && v.start_with?(get_session_key(env))
|
||||
bits = v.split(';')
|
||||
if bits.length > 0
|
||||
cookie_name_value = bits[0].split('=')
|
||||
if cookie_name_value.length == 1 && Rails.application.config.session_cookie_domain
|
||||
# this path indicates there is no value for the remember_token, i.e., it's being deleted
|
||||
::Rack::Utils.set_cookie_header!(
|
||||
headers, # contains response headers
|
||||
get_session_key(env), # gets the cookie session name, '_session_cookie' - for this example
|
||||
{ :value => '', :path => '/', :expires => Time.at(0) })
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if there_are_more_than_one_session_key_in_cookies?(env)
|
||||
delete_session_cookie_for_current_domain(env, headers)
|
||||
end
|
||||
|
||||
[status, headers, body]
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def there_are_more_than_one_session_key_in_cookies?(env)
|
||||
entries = 0
|
||||
offset = 0
|
||||
while offset = env["HTTP_COOKIE"].to_s.index(get_session_key(env), offset)
|
||||
entries += 1
|
||||
offset += 1
|
||||
end
|
||||
entries > 1
|
||||
end
|
||||
|
||||
|
||||
# Sets expiration date = 1970-01-01 to the cookie, this way browser will
|
||||
# note the cookie is expired and will delete it
|
||||
def delete_session_cookie_for_current_domain(env, headers)
|
||||
@@log.debug "deleting default domain session cookie"
|
||||
::Rack::Utils.set_cookie_header!(
|
||||
headers, # contains response headers
|
||||
get_session_key(env), # gets the cookie session name, '_session_cookie' - for this example
|
||||
{ :value => '', :path => '/', :expires => Time.at(0) }
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
def get_session_key(env)
|
||||
'remember_token'
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -59,6 +59,11 @@ namespace :db do
|
|||
make_recording
|
||||
end
|
||||
|
||||
# takes command line args: http://davidlesches.com/blog/passing-arguments-to-a-rails-rake-task
|
||||
task :populate_conversation, [:target_email] => :environment do |task, args|
|
||||
populate_conversation(args.target_email)
|
||||
end
|
||||
|
||||
desc "Fill database with music session sample data"
|
||||
task populate_music_sessions: :environment do
|
||||
make_users(10) if 14 > User.count
|
||||
|
|
@ -272,4 +277,19 @@ def make_recording
|
|||
mix.completed = true
|
||||
recording.mixes << mix
|
||||
recording.save!(validate:false)
|
||||
end
|
||||
|
||||
def populate_conversation(target_email)
|
||||
all_users = User.all
|
||||
|
||||
target_users = target_email ? User.where(email: target_email) : all_users
|
||||
|
||||
target_users.each do |target_user|
|
||||
all_users.each do |other_user|
|
||||
next if target_user == other_user
|
||||
20.times do
|
||||
FactoryGirl.create(:notification_text_message, target_user: target_user, source_user: other_user, message: Faker::Lorem.characters(rand(400)))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -34,11 +34,9 @@ describe SessionsController do
|
|||
post :create, :session => @attr
|
||||
response.should redirect_to(client_url)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "create_oauth" do
|
||||
|
||||
describe "create_oauth" do
|
||||
|
||||
describe "twitter" do
|
||||
|
||||
|
|
|
|||
|
|
@ -400,4 +400,12 @@ FactoryGirl.define do
|
|||
|
||||
factory :event_session, :class => JamRuby::EventSession do
|
||||
end
|
||||
|
||||
factory :notification, :class => JamRuby::Notification do
|
||||
|
||||
factory :notification_text_message do
|
||||
description 'TEXT_MESSAGE'
|
||||
message Faker::Lorem.characters(10)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ describe "Account", :js => true, :type => :feature, :capybara_feature => true do
|
|||
end
|
||||
|
||||
it {
|
||||
user.subscribe_email.should be_true
|
||||
user.subscribe_email.should be_true # we haven't user.reload yet
|
||||
should have_selector('h1', text: 'my account')
|
||||
should have_selector('#notification h2', text: 'Profile Changed')
|
||||
user.reload
|
||||
|
|
|
|||
|
|
@ -82,20 +82,10 @@ describe "Authentication", :js => true, :type => :feature, :capybara_feature =>
|
|||
|
||||
describe "after signing in" do
|
||||
|
||||
it "should render the desired protected page" do
|
||||
page.should have_title("JamKazam | Edit user")
|
||||
end
|
||||
|
||||
describe "when signing in again" do
|
||||
describe "when attempting to sign in again, should render the signed-in client page" do
|
||||
before do
|
||||
visit signin_path
|
||||
fill_in "Email", with: user.email
|
||||
fill_in "Password", with: user.password
|
||||
click_button "SIGN IN"
|
||||
end
|
||||
|
||||
it "should render the signed-in client page" do
|
||||
# it now goes to /music_sessions
|
||||
page.should have_title("JamKazam")
|
||||
page.should have_selector('h2', text: "musicians")
|
||||
end
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue