diff --git a/db/manifest b/db/manifest index fb64e8498..e51930a82 100755 --- a/db/manifest +++ b/db/manifest @@ -241,3 +241,5 @@ jam_track_available.sql active_jam_track.sql bpms_on_tap_in.sql jamtracks_job.sql +text_messages.sql +text_message_migration.sql \ No newline at end of file diff --git a/db/up/text_message_migration.sql b/db/up/text_message_migration.sql new file mode 100644 index 000000000..c4603c307 --- /dev/null +++ b/db/up/text_message_migration.sql @@ -0,0 +1,5 @@ +insert into text_messages(source_user_id, target_user_id, message, created_at, updated_at) ( + select source_user_id, target_user_id, message, created_at, updated_at + from notifications + where description='TEXT_MESSAGE' +); \ No newline at end of file diff --git a/db/up/text_messages.sql b/db/up/text_messages.sql new file mode 100644 index 000000000..4e8a10089 --- /dev/null +++ b/db/up/text_messages.sql @@ -0,0 +1,8 @@ +CREATE TABLE text_messages ( + id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(), + source_user_id VARCHAR(64) REFERENCES users(id) ON DELETE CASCADE, + target_user_id VARCHAR(64) REFERENCES users(id) ON DELETE CASCADE, + message TEXT NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); \ No newline at end of file diff --git a/ruby/lib/jam_ruby.rb b/ruby/lib/jam_ruby.rb index d89371770..084ae7d9e 100755 --- a/ruby/lib/jam_ruby.rb +++ b/ruby/lib/jam_ruby.rb @@ -197,6 +197,7 @@ require "jam_ruby/models/jam_company" require "jam_ruby/models/user_sync" require "jam_ruby/models/video_source" require "jam_ruby/models/recorded_video" +require "jam_ruby/models/text_message" require "jam_ruby/jam_tracks_manager" include Jampb diff --git a/ruby/lib/jam_ruby/amqp/amqp_connection_manager.rb b/ruby/lib/jam_ruby/amqp/amqp_connection_manager.rb index 644449b64..863bc1172 100644 --- a/ruby/lib/jam_ruby/amqp/amqp_connection_manager.rb +++ b/ruby/lib/jam_ruby/amqp/amqp_connection_manager.rb @@ -64,7 +64,7 @@ module JamRuby def on_recovery(conn, settings) @connected = true - @log.debug "reconnected #{conn} #{settings}" + @log.warn "reconnected #{conn} #{settings}" #puts "#channel before #{@channel}" #puts "recovered channel: #{@channel.reuse}" diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/welcome_message.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/welcome_message.html.erb index 6feeb3f66..439aefe3a 100644 --- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/welcome_message.html.erb +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/welcome_message.html.erb @@ -11,13 +11,13 @@
Getting Started Video
We recommend watching this video before you jump into the service just to get oriented. It will really help you hit the ground running:
-https://www.youtube.com/watch?v=VexH4834o9I
+https://www.youtube.com/watch?v=DBo--aj_P1w
Other Great Tutorial Videos
There are several other very great videos that will help you understand how to find and connect with other musicians on the service, create your own sessions or find and join other musicians’ sessions, play in sessions, record and share your performances, and even live broadcast your sessions to family, friends, and fans. Check these helpful videos out here:
-https://jamkazam.desk.com/customer/portal/articles/1304097-tutorial-videos
+https://jamkazam.desk.com/customer/portal/topics/673198-tutorials-on-major-features/articles
diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/welcome_message.text.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/welcome_message.text.erb
index ef28cd06c..90efc88ef 100644
--- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/welcome_message.text.erb
+++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/welcome_message.text.erb
@@ -3,12 +3,12 @@ Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
We're delighted that you have decided to try the JamKazam service, and we hope that you will enjoy using JamKazam to play music with others. Following are links to some resources that can help to get you up and running quickly.
Getting Started Video
-We recommend watching this video before you jump into the service just to get oriented. It will really help you hit the ground running:
-https://www.youtube.com/watch?v=VexH4834o9I
+We recommend watching this video before you jump into the service just to get oriented. It will really help you hit the ground running:
+https://www.youtube.com/watch?v=DBo--aj_P1w
Other Great Tutorial Videos
There are several other very great videos that will help you understand how to find and connect with other musicians on the service, create your own sessions or find and join other musicians’ sessions, play in sessions, record and share your performances, and even live broadcast your sessions to family, friends, and fans. Check these helpful videos out here:
-https://jamkazam.desk.com/customer/portal/articles/1304097-tutorial-videos
+https://jamkazam.desk.com/customer/portal/topics/673198-tutorials-on-major-features/articles
Knowledge Base Articles
You can find Getting Started knowledge base articles on things like frequently asked questions (FAQ), minimum system requirements for your Windows or Mac computer, how to troubleshoot audio problems in sessions, and more here:
diff --git a/ruby/lib/jam_ruby/connection_manager.rb b/ruby/lib/jam_ruby/connection_manager.rb
index 135238a02..bcf06b4c5 100644
--- a/ruby/lib/jam_ruby/connection_manager.rb
+++ b/ruby/lib/jam_ruby/connection_manager.rb
@@ -333,6 +333,8 @@ SQL
connection = Connection.find_by_client_id_and_user_id!(client_id, user.id)
connection.join_the_session(music_session, as_musician, tracks, user, audio_latency, video_sources)
+
+ JamRuby::MusicSessionUserHistory.join_music_session(user.id, music_session.id)
# connection.music_session_id = music_session.id
# connection.as_musician = as_musician
# connection.joining_session = true
diff --git a/ruby/lib/jam_ruby/models/active_music_session.rb b/ruby/lib/jam_ruby/models/active_music_session.rb
index 6dd93acc8..c28ae8de2 100644
--- a/ruby/lib/jam_ruby/models/active_music_session.rb
+++ b/ruby/lib/jam_ruby/models/active_music_session.rb
@@ -290,13 +290,8 @@ module JamRuby
}
)
- if (offset)
- query = query.offset(offset)
- end
-
- if (limit)
- query = query.limit(limit)
- end
+ query = query.offset(offset) if offset
+ query = query.limit(limit) if limit
if as_musician
query = query.where(
diff --git a/ruby/lib/jam_ruby/models/music_session.rb b/ruby/lib/jam_ruby/models/music_session.rb
index 375e3806c..a29d0b2f9 100644
--- a/ruby/lib/jam_ruby/models/music_session.rb
+++ b/ruby/lib/jam_ruby/models/music_session.rb
@@ -426,14 +426,19 @@ module JamRuby
# returns one user history per user, with instruments all crammed together, and with total duration
def unique_user_histories
+
+ # only get the active users if the session is in progress
+ user_filter = "music_sessions_user_history.session_removed_at is null" if self.session_removed_at.nil?
+
MusicSessionUserHistory
- .joins(:user)
- .select("STRING_AGG(instruments, '|') AS total_instruments,
- SUM(date_part('epoch', COALESCE(music_sessions_user_history.session_removed_at, music_sessions_user_history.created_at) - music_sessions_user_history.created_at)) AS total_duration,
- music_sessions_user_history.user_id, music_sessions_user_history.music_session_id, users.first_name, users.last_name, users.photo_url")
- .group("music_sessions_user_history.user_id, music_sessions_user_history.music_session_id, users.first_name, users.last_name, users.photo_url")
- .order("music_sessions_user_history.user_id")
- .where(%Q{ music_sessions_user_history.music_session_id = '#{id}'})
+ .joins(:user)
+ .select("STRING_AGG(instruments, '|') AS total_instruments,
+ SUM(date_part('epoch', COALESCE(music_sessions_user_history.session_removed_at, music_sessions_user_history.created_at) - music_sessions_user_history.created_at)) AS total_duration,
+ music_sessions_user_history.user_id, music_sessions_user_history.music_session_id, users.first_name, users.last_name, users.photo_url")
+ .group("music_sessions_user_history.user_id, music_sessions_user_history.music_session_id, users.first_name, users.last_name, users.photo_url")
+ .order("music_sessions_user_history.user_id")
+ .where(%Q{ music_sessions_user_history.music_session_id = '#{id}'})
+ .where(user_filter)
end
def duration_minutes
diff --git a/ruby/lib/jam_ruby/models/music_session_user_history.rb b/ruby/lib/jam_ruby/models/music_session_user_history.rb
index f79e2e810..430c897a1 100644
--- a/ruby/lib/jam_ruby/models/music_session_user_history.rb
+++ b/ruby/lib/jam_ruby/models/music_session_user_history.rb
@@ -56,6 +56,20 @@ module JamRuby
(end_time - self.created_at) / 60.0
end
+ def self.join_music_session(user_id, session_id)
+ hist = self
+ .where(:user_id => user_id)
+ .where(:music_session_id => session_id)
+ .limit(1)
+ .first
+ hist.start_history if hist
+ end
+
+ def start_history
+ self.session_removed_at = nil
+ self.update_attributes(:session_removed_at => self.session_removed_at, :max_concurrent_connections => determine_max_concurrent)
+ end
+
def self.removed_music_session(user_id, session_id)
hist = self
.where(:user_id => user_id)
@@ -67,7 +81,6 @@ module JamRuby
def end_history
self.session_removed_at = Time.now if self.session_removed_at.nil?
-
self.update_attributes(:session_removed_at => self.session_removed_at, :max_concurrent_connections => determine_max_concurrent)
end
diff --git a/ruby/lib/jam_ruby/models/notification.rb b/ruby/lib/jam_ruby/models/notification.rb
index 5fa628f3a..e0ec6590b 100644
--- a/ruby/lib/jam_ruby/models/notification.rb
+++ b/ruby/lib/jam_ruby/models/notification.rb
@@ -42,7 +42,7 @@ module JamRuby
# used for persisted notifications
def formatted_msg
# target_user, band, session, recording, invitation, join_request = nil
- source_user, band = nil
+ source_user, band, session = nil
unless self.source_user_id.nil?
source_user = User.find(self.source_user_id)
@@ -53,7 +53,12 @@ module JamRuby
end
unless self.session_id.nil?
- session = MusicSession.find(self.session_id)
+ session = MusicSession.find_by_id(self.session_id)
+
+ # remove all notifications related to this session if it's not found
+ if session.nil?
+ Notification.delete_all "(session_id = '#{session_id}')"
+ end
end
self.class.format_msg(self.description, {:user => source_user, :band => band, :session => session})
diff --git a/ruby/lib/jam_ruby/models/text_message.rb b/ruby/lib/jam_ruby/models/text_message.rb
new file mode 100644
index 000000000..c4a3a3d07
--- /dev/null
+++ b/ruby/lib/jam_ruby/models/text_message.rb
@@ -0,0 +1,52 @@
+include Devise::Models
+
+module JamRuby
+ class TextMessage < ActiveRecord::Base
+
+ self.primary_key = 'id'
+
+ default_scope order('created_at DESC')
+
+ attr_accessible :target_user_id, :source_user_id, :message
+
+ belongs_to :target_user, :class_name => "JamRuby::User", :foreign_key => "target_user_id"
+ belongs_to :source_user, :class_name => "JamRuby::User", :foreign_key => "source_user_id"
+
+ validates :message, length: {minimum: 1, maximum: 400}, no_profanity: true
+
+ def self.index(target_user_id, source_user_id, options = {})
+ offset = options[:offset]
+ limit = options[:limit]
+
+ # if not specified, default offset to 0
+ offset ||= 0
+ offset = offset.to_i
+
+ # if not specified, default limit to 10
+ limit ||= 10
+ limit = limit.to_i
+
+ TextMessage
+ .offset(offset)
+ .limit(limit)
+ .where('(source_user_id = (?) AND target_user_id = (?)) OR (source_user_id = (?) AND target_user_id = (?))', source_user_id, target_user_id, target_user_id, source_user_id)
+
+ end
+
+ def self.create(message, target_user_id, source_user_id)
+ sanitized_text = Sanitize.fragment(message, elements: HtmlSanitize::SAFE)
+
+ # create new message
+ tm = TextMessage.new
+ tm.message = sanitized_text
+ tm.target_user_id = target_user_id
+ tm.source_user_id = source_user_id
+ tm.save
+
+ # send notification
+ @notification = Notification.send_text_message(sanitized_text, User.find(source_user_id), User.find(target_user_id))
+
+ tm
+ end
+ end
+end
\ No newline at end of file
diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb
index a5ea8b827..c59021903 100644
--- a/ruby/lib/jam_ruby/models/user.rb
+++ b/ruby/lib/jam_ruby/models/user.rb
@@ -25,6 +25,10 @@ module JamRuby
MOD_NO_SHOW = "no_show"
+ # MIN/MAX AUDIO LATENCY
+ MINIMUM_AUDIO_LATENCY = 2
+ MAXIMUM_AUDIO_LATENCY = 10000
+
devise :database_authenticatable, :recoverable, :rememberable
acts_as_mappable
@@ -79,6 +83,9 @@ module JamRuby
# self.id = followable_id in follows table
has_many :followers, :as => :followable, :class_name => "JamRuby::Follow", :dependent => :destroy
+ # text messages
+ has_many :text_messages, :class_name => "JamRuby:TextMessage", :foreign_key => "target_user_id"
+
# notifications
has_many :notifications, :class_name => "JamRuby::Notification", :foreign_key => "target_user_id"
has_many :inverse_notifications, :through => :notifications, :class_name => "JamRuby::User"
@@ -163,7 +170,7 @@ module JamRuby
validates :musician, :inclusion => {:in => [true, false]}
validates :show_whats_next, :inclusion => {:in => [nil, true, false]}
validates :mods, json: true
- validates_numericality_of :last_jam_audio_latency, greater_than:0, :allow_nil => true
+ validates_numericality_of :last_jam_audio_latency, greater_than:MINIMUM_AUDIO_LATENCY, less_than:MAXIMUM_AUDIO_LATENCY, :allow_nil => true
validates :last_jam_updated_reason, :inclusion => {:in => [nil, JAM_REASON_REGISTRATION, JAM_REASON_NETWORK_TEST, JAM_REASON_FTUE, JAM_REASON_JOIN, JAM_REASON_IMPORT, JAM_REASON_LOGIN] }
# custom validators
@@ -1017,6 +1024,8 @@ module JamRuby
user.save
+ user.errors.add("recaptcha", "verification failed") if recaptcha_failed
+
if user.errors.any?
raise ActiveRecord::Rollback
else
@@ -1033,16 +1042,9 @@ module JamRuby
UserMailer.confirm_email(user, signup_confirm_url.nil? ? nil : (signup_confirm_url + "/" + user.signup_token) ).deliver
end
end
-
- if recaptcha_failed
- user.errors.add "recaptcha", "verification failed"
- raise ActiveRecord::Rollback
- end
-
end
-
- return user
- end
+ user
+ end # def signup
# this is intended to be development-mode or test-mode only; VRFS-149
# it creates or updates one user per developer, so that we aren't in the business
@@ -1379,8 +1381,9 @@ module JamRuby
end
def update_audio_latency(connection, audio_latency)
- if audio_latency > 2
- # updating the connection is best effort
+ # the backend sometimes gives tiny numbers, and sometimes very large numbers
+ if audio_latency > MINIMUM_AUDIO_LATENCY && audio_latency < MAXIMUM_AUDIO_LATENCY
+ # updating the connection is best effort; if it's not there that's OK
if connection
Connection.where(:id => connection.id).update_all(:last_jam_audio_latency => audio_latency)
end
diff --git a/ruby/lib/jam_ruby/resque/resque_hooks.rb b/ruby/lib/jam_ruby/resque/resque_hooks.rb
index fcd344bf6..e58298569 100644
--- a/ruby/lib/jam_ruby/resque/resque_hooks.rb
+++ b/ruby/lib/jam_ruby/resque/resque_hooks.rb
@@ -11,7 +11,10 @@ def shutdown
end
Resque.before_first_fork do
- JamWebEventMachine.start
+ current = Thread.current
+ Thread.new do
+ JamWebEventMachine.run_em(current)
+ end
#ActiveRecord::Base.establish_connection
config = {
@@ -41,6 +44,9 @@ Resque.before_fork do
# ActiveRecord::Base.connection.disconnect!
#JamRuby::Stats.destroy!
+
+ # reconnect between jobs
+ ActiveRecord::Base.connection_handler.verify_active_connections!
end
Resque.after_fork do
diff --git a/ruby/spec/jam_ruby/models/text_message.spec.rb b/ruby/spec/jam_ruby/models/text_message.spec.rb
new file mode 100644
index 000000000..7b612b3ac
--- /dev/null
+++ b/ruby/spec/jam_ruby/models/text_message.spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+
+describe TextMessage do
+
+ before do
+ TextMessage.delete_all
+ User.delete_all
+ @target_user = FactoryGirl.create(:user)
+ @source_user = FactoryGirl.create(:user)
+
+ @msg = TextMessage.new(:target_user_id => @target_user.id, :source_user_id => @source_user.id)
+ end
+
+ describe "index" do
+
+ it "should retrieve conversation for both users" do
+ @msg.message = "Test message"
+ @msg.save!
+
+ messages = TextMessage.index(@target_user.id, @source_user.id)
+ messages.count.should == 1
+
+ messages = TextMessage.index(@source_user.id, @target_user.id)
+ messages.count.should == 1
+ end
+
+ it "should page records" do
+ 11.times do |n|
+ message = TextMessage.new(:target_user_id => @target_user.id, :source_user_id => @source_user.id)
+ message.message = "Message #{n}"
+ message.save!
+ end
+
+ messages = TextMessage.index(@target_user.id, @source_user.id, {:offset => 0})
+ messages.count.should == 10
+
+ messages = TextMessage.index(@target_user.id, @source_user.id, {:offset => 10})
+ messages.count.should == 1
+ end
+
+ it "should not allow empty message" do
+ expect { @msg.save! }.to raise_error(ActiveRecord::RecordInvalid)
+ end
+
+ end
+end
\ No newline at end of file
diff --git a/ruby/spec/jam_ruby/models/user_spec.rb b/ruby/spec/jam_ruby/models/user_spec.rb
index 4fd3d2040..ec8b8440d 100644
--- a/ruby/spec/jam_ruby/models/user_spec.rb
+++ b/ruby/spec/jam_ruby/models/user_spec.rb
@@ -489,14 +489,14 @@ describe User do
describe "audio latency" do
it "allow update" do
- @user.last_jam_audio_latency = 1
+ @user.last_jam_audio_latency = 5
@user.save!
end
- it "prevent negative or 0" do
- @user.last_jam_audio_latency = 0
+ it "prevent negative" do
+ @user.last_jam_audio_latency = -1
@user.save.should be_false
- @user.errors[:last_jam_audio_latency].should == ['must be greater than 0']
+ @user.errors[:last_jam_audio_latency].should == ['must be greater than 2']
end
it "prevent non numerical" do
@@ -504,6 +504,42 @@ describe User do
@user.save.should be_false
@user.errors[:last_jam_audio_latency].should == ['is not a number']
end
+
+ it "prevent 2 (minimum)" do
+ @user.last_jam_audio_latency = User::MINIMUM_AUDIO_LATENCY
+ @user.save.should be_false
+ @user.errors[:last_jam_audio_latency].should == ['must be greater than 2']
+ end
+
+ it "prevent 10000 (maximum)" do
+ @user.last_jam_audio_latency = User::MAXIMUM_AUDIO_LATENCY
+ @user.save.should be_false
+ @user.errors[:last_jam_audio_latency].should == ['must be less than 10000']
+ end
+ end
+
+ describe "update_audio_latency" do
+
+ before(:each) do
+ @user.last_jam_audio_latency.should be_nil
+ end
+
+ it "ignores low latency" do
+ @user.update_audio_latency(nil, User::MINIMUM_AUDIO_LATENCY)
+ @user.last_jam_audio_latency.should be_nil
+ end
+
+ it "ignores high latency" do
+ @user.last_jam_audio_latency.should be_nil
+ @user.update_audio_latency(nil, User::MAXIMUM_AUDIO_LATENCY)
+ @user.last_jam_audio_latency.should be_nil
+ end
+
+ it "accepts normal latency" do
+ @user.last_jam_audio_latency.should be_nil
+ @user.update_audio_latency(nil, User::MINIMUM_AUDIO_LATENCY + 1)
+ @user.last_jam_audio_latency.should == User::MINIMUM_AUDIO_LATENCY + 1
+ end
end
describe "html_sanitize" do
diff --git a/web/Gemfile b/web/Gemfile
index eda57ee0a..e5c3f1583 100644
--- a/web/Gemfile
+++ b/web/Gemfile
@@ -65,7 +65,6 @@ gem 'postgres-copy'
#end
gem 'geokit-rails'
gem 'postgres_ext'
-gem 'recaptcha', '0.3.6'
gem 'resque'
gem 'resque-retry'
gem 'resque-failed-job-mailer'
diff --git a/web/app/assets/javascripts/accounts_session_detail.js b/web/app/assets/javascripts/accounts_session_detail.js
index d75a5ea2e..82c028e52 100644
--- a/web/app/assets/javascripts/accounts_session_detail.js
+++ b/web/app/assets/javascripts/accounts_session_detail.js
@@ -339,7 +339,14 @@
if ("instrument_list" in pending_rsvp_request && pending_rsvp_request.instrument_list != null) {
$.each(pending_rsvp_request.instrument_list, function (index, instrument) {
- var instrumentId = context.JK.getInstrumentId(instrument.id);
+ var instrumentId;
+
+ if (instrument) {
+ instrumentId = context.JK.getInstrumentId(instrument.id);
+ }
+ else {
+ instrumentId = 'other';
+ }
var inst = context.JK.getInstrumentIcon24(instrumentId);
instrumentLogoHtml += ' ';
instrumentDesc.push(instrumentId);
@@ -378,7 +385,14 @@
$.each(sessionData.approved_rsvps, function(index, approved_rsvp) {
if ("instrument_list" in approved_rsvp) {
$.each(approved_rsvp.instrument_list, function(index, instrument) {
- var instrumentId = context.JK.getInstrumentId(instrument.id);
+ var instrumentId;
+
+ if (instrument) {
+ instrumentId = context.JK.getInstrumentId(instrument.id);
+ }
+ else {
+ instrumentId = 'other';
+ }
var inst = context.JK.getInstrumentIcon24(instrumentId);
instrumentLogoHtml += '
';
});
diff --git a/web/app/assets/javascripts/dialog/sessionStartDialog.js b/web/app/assets/javascripts/dialog/sessionStartDialog.js
new file mode 100644
index 000000000..971a5da65
--- /dev/null
+++ b/web/app/assets/javascripts/dialog/sessionStartDialog.js
@@ -0,0 +1,130 @@
+(function(context,$) {
+
+ "use strict";
+ context.JK = context.JK || {};
+ context.JK.SessionStartDialog = function(app, session) {
+ var logger = context.JK.logger;
+ var sessionUtils = context.JK.SessionUtils;
+ var $dialog = null;
+ var dialogId = 'session-start-dialog';
+ var $btnStartSession = null;
+
+ function beforeShow(data) {
+ }
+
+ function afterShow(data) {
+ }
+
+ function afterHide() {
+ }
+
+ function showDialog() {
+ return app.layout.showDialog(dialogId);
+ }
+
+ function events() {
+ $btnStartSession.unbind('click');
+ $btnStartSession.click(function(e) {
+ context.location = '/client#/session/' + session.id;
+ app.layout.closeDialog(dialogId);
+ });
+ }
+
+ function initializeSessionDetails() {
+ $dialog.find('#session-start-type-disp').html('Now!');
+ $dialog.find('#session-name-disp').html(session.name);
+ $dialog.find('#session-description-disp').html(session.description);
+
+ if (session.music_notations && session.music_notations.length > 0) {
+ $dialog.find('#session-notations-disp').html("Notations: " + session.music_notations.join(', '));
+ }
+
+ if (session.band) {
+ $dialog.find('#session-band-disp').html(band.name);
+ }
+ else {
+ $dialog.find('#session-band-disp').html('N/A');
+ }
+
+ $dialog.find('#session-language-disp').html(session.language_description);
+
+ var invitedFriends = session.invitations;
+
+ var sessionInvited = [];
+ $.each(invitedFriends, function(index, invitation) {
+ sessionInvited.push(invitation.receiver_name);
+ });
+
+ var sessionInvitedString = sessionInvited.join(', ');
+
+ if (session.musician_access && session.approval_required) {
+ if (session.open_rsvps) {
+ if (invitedFriends.length == 0)
+ sessionInvitedString = "Any interested JamKazam musicians that I approve";
+ else
+ sessionInvitedString += ", plus any interested JamKazam musicians that I approve";
+ }
+ else {
+ if (invitedFriends.length == 0) {
+ sessionInvitedString = "No open RSVPs";
+ }
+ else {
+ sessionInvitedString += " (No open RSVPs)";
+ }
+ }
+ }
+ else if (session.musician_access && !session.approval_required) {
+ if (invitedFriends.length == 0)
+ sessionInvitedString = "Any interested JamKazam musicians who want to join us";
+ else
+ sessionInvitedString += ", plus any interested JamKazam musicians who want to join us";
+ }
+
+ $dialog.find('#session-invited-disp').html(sessionInvitedString);
+
+ var instrumentsMe = [], instrumentsOthers = [];
+
+ $.each(session.approved_rsvps, function(index, rsvp) {
+ if (rsvp.id === context.JK.currentUserId) {
+ $.each(rsvp.instrument_list, function(index, instrument) {
+ instrumentsMe.push(instrument.desc);
+ });
+ }
+ else {
+ $.each(rsvp.instrument_list, function(index, instrument) {
+ instrumentsOthers.push(instrument.desc);
+ });
+ }
+ });
+
+ $dialog.find('#session-instruments-me-disp').html(instrumentsMe.join(', '));
+ $dialog.find('#session-instruments-rsvp-disp').html(instrumentsOthers.join(', '));
+
+ $dialog.find('#session-musician-access-disp').html('Musicians: ' + session.musician_access_description);
+ $dialog.find('#session-fans-access-disp').html('Fans: ' + session.fan_access_description);
+ $dialog.find('#session-policy-disp').html(session.legal_policy);
+ }
+
+ function initialize() {
+
+ var dialogBindings = {
+ 'beforeShow' : beforeShow,
+ 'afterShow' : afterShow,
+ 'afterHide': afterHide
+ };
+
+ app.bindDialog(dialogId, dialogBindings);
+
+ $dialog = $('[layout-id="' + dialogId + '"]');
+ $btnStartSession = $dialog.find('.btnStartSession');
+
+ initializeSessionDetails();
+ events();
+ }
+
+ this.initialize = initialize;
+ this.showDialog = showDialog;
+ }
+
+ return this;
+})(window,jQuery);
\ No newline at end of file
diff --git a/web/app/assets/javascripts/dialog/textMessageDialog.js b/web/app/assets/javascripts/dialog/textMessageDialog.js
index 78107a7f9..d83f0efb5 100644
--- a/web/app/assets/javascripts/dialog/textMessageDialog.js
+++ b/web/app/assets/javascripts/dialog/textMessageDialog.js
@@ -37,14 +37,14 @@
}
function buildParams() {
- return { type: 'TEXT_MESSAGE', receiver: otherId, offset: offset, limit: LIMIT};
+ return { target_user_id: otherId, offset: offset, limit: LIMIT};
}
function buildMessage() {
var message = {};
message['message'] = $textBox.val();
- message['receiver'] = otherId;
+ message['target_user_id'] = otherId;
return message;
}
@@ -66,17 +66,17 @@
$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');
- })
+ .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;
@@ -163,7 +163,7 @@
}
$sendTextMessage.click(sendMessage);
- rest.getNotifications(buildParams())
+ rest.getTextMessages(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);
diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js
index 2278fd333..c02cee31c 100644
--- a/web/app/assets/javascripts/jam_rest.js
+++ b/web/app/assets/javascripts/jam_rest.js
@@ -1262,13 +1262,24 @@
var id = getId(options);
return $.ajax({
type: "POST",
- url: '/api/users/' + id + '/notifications',
+ url: '/api/text_messages',
dataType: "json",
contentType: 'application/json',
data: JSON.stringify(options)
});
}
+ function getTextMessages(options) {
+ if(!options) options = {};
+ var id = getId(options);
+ return $.ajax({
+ type: "GET",
+ url: '/api/text_messages?' + $.param(options),
+ dataType: "json",
+ contentType: 'application/json'
+ });
+ }
+
function getNotifications(options) {
if(!options) options = {};
var id = getId(options);
@@ -1597,6 +1608,7 @@
this.tweet = tweet;
this.createFbInviteUrl = createFbInviteUrl;
this.createTextMessage = createTextMessage;
+ this.getTextMessages = getTextMessages;
this.getNotifications = getNotifications;
this.createChatMessage = createChatMessage;
this.getChatMessages = getChatMessages;
diff --git a/web/app/assets/javascripts/notificationPanel.js b/web/app/assets/javascripts/notificationPanel.js
index 41fa918c4..fdf0ac3ee 100644
--- a/web/app/assets/javascripts/notificationPanel.js
+++ b/web/app/assets/javascripts/notificationPanel.js
@@ -207,20 +207,25 @@
isLoading = true;
// retrieve pending notifications for this user
rest.getNotifications(buildParams())
- .done(function(response) {
- updateNotificationList(response);
- isLoading = false;
- })
- .fail(function() {
- isLoading = false;
- app.ajaxError();
- })
+ .done(function(response) {
+ updateNotificationList(response);
+ isLoading = false;
+ })
+ .fail(function() {
+ isLoading = false;
+ app.ajaxError();
+ })
}
function updateNotificationList(response) {
$.each(response, function(index, val) {
- if(val.description == 'TEXT_MESSAGE') {
+ // this means the session no longer exists
+ if (response.fan_access == null && response.musician_access == null) {
+ return;
+ }
+
+ if(val.description == context.JK.MessageType.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();
}
diff --git a/web/app/assets/javascripts/scheduled_session.js.erb b/web/app/assets/javascripts/scheduled_session.js.erb
index ebbd6a9b3..969f9449d 100644
--- a/web/app/assets/javascripts/scheduled_session.js.erb
+++ b/web/app/assets/javascripts/scheduled_session.js.erb
@@ -200,14 +200,14 @@
createSessionSettings.startDate = createSessionSettings.startDate || (new Date().toDateString());
- $("#session-start-date").val(createSessionSettings.startDate);
+ $screen.find("#session-start-date").val(createSessionSettings.startDate);
toggleDate(true);
toggleStartTime();
toggleStepStatus();
sessionUtils.defaultTimezone($timezoneList);
if(firstTimeShown) {
firstTimeShown = false;
- $('#session-when-start-scheduled').iCheck('check');
+ $screen.find('#session-when-start-scheduled').iCheck('check');
}
}
@@ -217,7 +217,7 @@
function beforeShowStep3() {
rest.getBands(context.JK.currentUserId)
.done(function(result) {
- var options = $("#session-band-list");
+ var options = $screen.find("#session-band-list");
options.empty();
options.append($("").val('').text('No'));
$.each(result, function(idx, item) {
@@ -251,10 +251,10 @@
var sessionName = createSessionSettings.name;
sessionName += ' (' + createSessionSettings.genresValues[0] + ')';
- $('#session-name-disp').html(sessionName);
+ $screen.find('#session-name-disp').html(sessionName);
var sessionDescription = createSessionSettings.description;
- $('#session-description-disp').html(sessionDescription);
+ $screen.find('#session-description-disp').html(sessionDescription);
var sessionNotations = [];
for (var i = 0; i < createSessionSettings.notations.length; i++) {
@@ -262,16 +262,16 @@
sessionNotations.push(name);
}
if(sessionNotations.length > 0) {
- $('#session-notations-disp').html("Notations: " + sessionNotations.join(', '));
+ $screen.find('#session-notations-disp').html("Notations: " + sessionNotations.join(', '));
}
else {
- $('#session-notations-disp').html('');
+ $screen.find('#session-notations-disp').html('');
}
- $('#session-language-disp').html(createSessionSettings.language.label);
- $('#session-band-disp').html(createSessionSettings.band.label);
+ $screen.find('#session-language-disp').html(createSessionSettings.language.label);
+ $screen.find('#session-band-disp').html(createSessionSettings.band.label);
- var plusMusicians = $('#session-plus-musicians')[0].checked;
+ var plusMusicians = $screen.find('#session-plus-musicians')[0].checked;
var sessionInvited = [];
var invitedFriends = inviteMusiciansUtil.getInvitedFriendNames();
@@ -302,7 +302,7 @@
else
sessionInvitedString += ", plus any interested JamKazam musicians who want to join us";
}
- $('#session-invited-disp').html(sessionInvitedString);
+ $screen.find('#session-invited-disp').html(sessionInvitedString);
if (createSessionSettings.createType == '<%= MusicSession::CREATE_TYPE_START_SCHEDULED%>') {
var session = scheduledSessions[createSessionSettings.selectedSessionId];
@@ -315,7 +315,7 @@
});
}
});
- $('#session-instruments-me-disp').html(instruments_me.join(', '));
+ $screen.find('#session-instruments-me-disp').html(instruments_me.join(', '));
}
if (session.open_slots.length > 0) {
@@ -334,7 +334,7 @@
$.map(instruments_rsvp_arr, function(val, i) {
instruments_str_arr.push(i + ' (' + val.count + ') (' + val.level + ')');
})
- $('#session-instruments-rsvp-disp').html(instruments_str_arr.join(', '));
+ $screen.find('#session-instruments-rsvp-disp').html(instruments_str_arr.join(', '));
}
}
else {
@@ -342,7 +342,7 @@
$.each(getCreatorInstruments(), function(index, instrument) {
instruments_me.push(instrument.name);
});
- $('#session-instruments-me-disp').html(instruments_me.join(', '));
+ $screen.find('#session-instruments-me-disp').html(instruments_me.join(', '));
var instruments_rsvp = [];
var otherInstruments = instrumentRSVP.getSelectedInstruments();
@@ -353,13 +353,13 @@
$.each(otherInstruments, function(index, instrument) {
instruments_rsvp.push(instrument.name + ' (' + instrument.count + ') (' + proficiencyDescriptionMap[instrument.level] + ')');
});
- $('#session-instruments-rsvp-disp').html(instruments_rsvp.join(', '));
+ $screen.find('#session-instruments-rsvp-disp').html(instruments_rsvp.join(', '));
}
- $('#session-musician-access-disp').html('Musicians: ' + createSessionSettings.musician_access.label);
- $('#session-fans-access-disp').html('Fans: ' + createSessionSettings.fans_access.label);
+ $screen.find('#session-musician-access-disp').html('Musicians: ' + createSessionSettings.musician_access.label);
+ $screen.find('#session-fans-access-disp').html('Fans: ' + createSessionSettings.fans_access.label);
- $('#session-policy-disp').html(createSessionSettings.session_policy);
+ $screen.find('#session-policy-disp').html(createSessionSettings.session_policy);
}
function beforeMoveStep1() {
@@ -428,7 +428,7 @@
createSessionSettings.recurring_mode.value = 'once';
}
else {
- createSessionSettings.startDate = $('#session-start-date').val();
+ createSessionSettings.startDate = $screen.find('#session-start-date').val();
createSessionSettings.startTime = $startTimeList.val();
createSessionSettings.endTime = $endTimeList.val();
createSessionSettings.notations = [];
@@ -437,7 +437,7 @@
createSessionSettings.timezone.label = $timezoneList.get(0).options[$timezoneList.get(0).selectedIndex].text;
createSessionSettings.recurring_mode.label = $recurringModeList.get(0).options[$recurringModeList.get(0).selectedIndex].text;
createSessionSettings.recurring_mode.value = $recurringModeList.val();
- createSessionSettings.open_rsvps = $('#session-plus-musicians')[0].checked;
+ createSessionSettings.open_rsvps = $screen.find('#session-plus-musicians')[0].checked;
}
return true;
@@ -503,22 +503,22 @@
function beforeMoveStep2() {
var isValid = true;
- var name = $('#session-name').val();
+ var name = $screen.find('#session-name').val();
if (!name) {
$('#divSessionName .error-text').remove();
$('#divSessionName').addClass("error");
- $('#session-name').after("
- Musicians can enjoy four major features of the new JamKazam service, as described below. Also, several Tutorial Videos are available to see how various features work in more detail. + Musicians can enjoy four major features of the new JamKazam service, as described below. Also, several Tutorial Videos are available to see how various features work in more detail.
- Also, several Tutorial Videos are available to see how various features work in more detail. + Also, several Tutorial Videos are available to see how various features work in more detail.
\ No newline at end of file diff --git a/web/app/views/dialogs/_dialogs.html.haml b/web/app/views/dialogs/_dialogs.html.haml index b7b15976c..56ec88ccc 100644 --- a/web/app/views/dialogs/_dialogs.html.haml +++ b/web/app/views/dialogs/_dialogs.html.haml @@ -18,6 +18,7 @@ = render 'dialogs/rsvpSubmitDialog' = render 'dialogs/rsvpCancelDialog' = render 'dialogs/rsvpCreateSlotDialog' += render 'dialogs/sessionStartDialog' = render 'dialogs/sessionCancelDialog' = render 'dialogs/signinDialog' = render 'dialogs/signupDialog' diff --git a/web/app/views/dialogs/_sessionStartDialog.html.slim b/web/app/views/dialogs/_sessionStartDialog.html.slim new file mode 100644 index 000000000..5117beca0 --- /dev/null +++ b/web/app/views/dialogs/_sessionStartDialog.html.slim @@ -0,0 +1,44 @@ +.dialog.dialog-overlay-lg layout='dialog' layout-id='session-start-dialog' id='session-start-dialog' + .content-head + = image_tag "content/icon_add.png", {:width => 24, :height => 24, :class => 'content-icon' } + h1 Start Session + + .dialog-inner + .session-wrapper + .left.w55 + h3 When are you starting your session? + .mt5 id='session-start-type-disp' + h3.mb5.mt20 What are you playing? + em id='session-name-disp' + #session-description-disp.mt5 + #session-notations-disp.mt5 + + h3.mt20 Which band is playing? + #session-band-disp.mt5 + + h3.mt20 What language will be spoken? + #session-language-disp.mt5 + .right.w40 + h3 Who is invited? + #session-invited-disp.mt5 + + h3.mt20 What instruments/parts do you need? + .left.ib.w20.mt5 Me: + #session-instruments-me-disp.left.ib.w75.mt5 + .clearall.left.ib.w20.mt5 Others: + #session-instruments-rsvp-disp.left.ib.w75.mt5 + br clear='all' + + h3.mt20 What access policies are in effect? + #session-musician-access-disp.mt5 + #session-fans-access-disp + + h3.mt20 What legal policy is in effect? + #session-policy-disp.mt5 + .clearall + br + br + .buttons + .right + a.button-grey class='btnCancel' layout-action='cancel' CANCEL + a.button-orange class='btnStartSession' START SESSION \ No newline at end of file diff --git a/web/config/routes.rb b/web/config/routes.rb index 4b81b4224..327ae86a1 100644 --- a/web/config/routes.rb +++ b/web/config/routes.rb @@ -295,6 +295,10 @@ SampleApp::Application.routes.draw do match '/users/:id/friends/:friend_id' => 'api_users#friend_show', :via => :get, :as => 'api_friend_detail' match '/users/:id/friends/:friend_id' => 'api_users#friend_destroy', :via => :delete + # text messages + match '/text_messages' => 'api_text_messages#index', :via => :get + match '/text_messages' => 'api_text_messages#create', :via => :post + # notifications match '/users/:id/notifications' => 'api_users#notification_index', :via => :get match '/users/:id/notifications/:notification_id' => 'api_users#notification_destroy', :via => :delete diff --git a/web/lib/you_tube_client.rb b/web/lib/google_client.rb similarity index 88% rename from web/lib/you_tube_client.rb rename to web/lib/google_client.rb index cba813844..c622a6e5f 100644 --- a/web/lib/you_tube_client.rb +++ b/web/lib/google_client.rb @@ -9,7 +9,7 @@ require 'socket' # Youtube OAuth and API functionality: module JamRuby - class YouTubeClient + class GoogleClient attr_accessor :client attr_accessor :api attr_accessor :request @@ -27,7 +27,7 @@ module JamRuby :application_version => '1.0.0' ) - youtube = client.discovered_api('youtube', 'v3') + #youtube = client.discovered_api('youtube', 'v3') end # Return a login URL that will show a web page with @@ -52,7 +52,7 @@ module JamRuby # https://developers.google.com/youtube/v3/docs/videos/insert # https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol - def upload_sign(user, filename, length) + def sign_youtube_upload(user, filename, length) raise ArgumentError, "Length is required and should be > 0" if length.to_i.zero? # Something like this: @@ -140,7 +140,7 @@ module JamRuby end # https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol#Check_Upload_Status - def get_upload_status(user, upload_url, length) + def youtube_upload_status(user, upload_url, length) auth = UserAuthorization.google_auth(user).first if auth.nil? || auth.token.nil? raise SecurityError, "No current google token found for user #{user}" @@ -187,21 +187,50 @@ module JamRuby end # @return true if file specified by URL uploaded, false otherwise - def verify_upload(user, upload_url, length) - status_hash=get_upload_status(user, upload_url, length) + def verify_youtube_upload(user, upload_url, length) + status_hash=youtube_upload_status(user, upload_url, length) (status_hash['status']>=200 && status_hash['status']<300) end # Set fully_uploaded if the upload can be verified. # @return true if verified; false otherwise: def complete_upload(recorded_video) - if (verify_upload(recorded_video.user, recorded_video.url, recorded_video.length)) + if (verify_youtube_upload(recorded_video.user, recorded_video.url, recorded_video.length)) recorded_video.update_attribute(:fully_uploaded, true) else false end end + def verify_recaptcha(recaptcha_response) + success = false + if !Rails.application.config.recaptcha_enable + success = true + else + Rails.logger.info "Login with: #{recaptcha_response}" + RestClient.get("https://www.google.com/recaptcha/api/siteverify", + params: { + secret: Rails.application.config.recaptcha_private_key, + response: recaptcha_response + } + ) do |response, request, result| + Rails.logger.info "response: #{response.inspect}" + case(response.code) + when 200..207 + json = JSON.parse(response.to_str) + if json['success'] + success = true + else + Rails.logger.info("Error verifying recaptcha: #{json['error-codes'].inspect}") + end + else + Rails.logger.info("Unexpected status from google_recaptcha: [#{response.code}] with headers: #{response.headers.inspect}") + end #case + end #do + end # if + success + end #def + # This will also sign in and prompt for login as necessary; # currently requires the server to be running at localhost:3000 def signin_flow() diff --git a/web/lib/user_manager.rb b/web/lib/user_manager.rb index a694af94c..5c36c6974 100644 --- a/web/lib/user_manager.rb +++ b/web/lib/user_manager.rb @@ -1,8 +1,10 @@ +require 'google_client' class UserManager < BaseManager def initialize(options={}) super(options) @log = Logging.logger[self] + @google_client = GoogleClient.new() end # Note that almost everything can be nil here. This is because when users sign up via social media, @@ -24,7 +26,8 @@ class UserManager < BaseManager fb_signup = options[:fb_signup] signup_confirm_url = options[:signup_confirm_url] affiliate_referral_id = options[:affiliate_referral_id] - recaptcha_failed = Rails.application.config.recaptcha_enable && options[:recaptcha_failed] + recaptcha_failed=(fb_signup) ? false : !@google_client.verify_recaptcha(options[:recaptcha_response]) + user = User.new # check if we have disabled open signup for this site. open == invited users can still get in diff --git a/web/spec/features/find_sessions_spec.rb b/web/spec/features/find_sessions_spec.rb index ba8f7c517..5853c13ce 100644 --- a/web/spec/features/find_sessions_spec.rb +++ b/web/spec/features/find_sessions_spec.rb @@ -192,6 +192,120 @@ describe "Find Session", :js => true, :type => :feature, :capybara_feature => tr end end + describe "start session behavior" do + before(:each) do + + @music_session = FactoryGirl.create(:music_session, creator: user) + + @invited_user = FactoryGirl.create(:user) + FactoryGirl.create(:friendship, :user => @invited_user, :friend => user) + FactoryGirl.create(:friendship, :user => user, :friend => @invited_user) + @invitation = FactoryGirl.create(:invitation, :sender => user, :receiver => @invited_user, :music_session => @music_session) + + @rsvp_user = FactoryGirl.create(:user) + @rsvp_slot = FactoryGirl.create(:rsvp_slot, music_session: @music_session) + @rsvp_request = FactoryGirl.create(:rsvp_request_for_slots, chosen: nil, user: @rsvp_user, slots: [@rsvp_slot]) + end + + it "should always show start session link for session creator" do + pending + fast_signin(user, Nav.find_session) + find("#sessions-scheduled .rsvp-msg span.text a.start", text: "Start session now?") + fast_signout + end + + it "should not show start session link for anyone who is not creator, invitee, or RSVP user" do + pending + random_user = FactoryGirl.create(:user) + fast_signin(random_user, Nav.find_session) + page.should have_no_selector("#sessions-scheduled .rsvp-msg span.text a.start") + fast_signout + end + + it "should show start session link for invited or RSVP users" do + pending + # make session date/time TBD + @music_session.scheduled_start = Time.now + 5.minutes + @music_session.save! + + # invited user + fast_signin(@invited_user, Nav.find_session) + page.should have_selector("#sessions-scheduled .rsvp-msg span.text a.start", text: "Start session now?") + fast_signout + + # RSVP user + fast_signin(@rsvp_user, Nav.find_session) + page.should have_no_selector("#sessions-scheduled .rsvp-msg span.text a.start", text: "Start session now?") + page.should have_selector("#sessions-scheduled .rsvp-msg span.text a.cancel", text: "Cancel RSVP") + fast_signout + + # now approve the RSVP + @rsvp_request.rsvp_requests_rsvp_slots[0].chosen = true + @rsvp_request.rsvp_requests_rsvp_slots[0].save! + + fast_signin(@rsvp_user, Nav.find_session) + page.should have_selector("#sessions-scheduled .rsvp-msg span.text a.start", text: "Start session now?") + page.should have_selector("#sessions-scheduled .rsvp-msg span.text a.cancel", text: "Cancel RSVP") + fast_signout + end + + it "should not show start session link for invited or RSVP users when date/time is TBD" do + pending + # make session date/time TBD + @music_session.scheduled_start = nil + @music_session.save! + + # invited user + fast_signin(@invited_user, Nav.find_session) + page.should have_no_selector("#sessions-scheduled .rsvp-msg span.text a.start", text: "Start session now?") + fast_signout + + # RSVP user + fast_signin(@rsvp_user, Nav.find_session) + page.should have_no_selector("#sessions-scheduled .rsvp-msg span.text a.start", text: "Start session now?") + page.should have_selector("#sessions-scheduled .rsvp-msg span.text a.cancel", text: "Cancel RSVP") + fast_signout + + # now approve the RSVP + @rsvp_request.rsvp_requests_rsvp_slots[0].chosen = true + @rsvp_request.rsvp_requests_rsvp_slots[0].save! + + # "start session" should still be hidden + fast_signin(@rsvp_user, Nav.find_session) + page.should have_no_selector("#sessions-scheduled .rsvp-msg span.text a.start", text: "Start session now?") + page.should have_selector("#sessions-scheduled .rsvp-msg span.text a.cancel", text: "Cancel RSVP") + fast_signout + end + + it "should not show start session link for invited or RSVP users when more than 15 minutes remain to start time" do + pending + # make session date/time more than 15 min away + @music_session.scheduled_start = Time.now + 60.minutes + @music_session.save! + + # invited user + fast_signin(@invited_user, Nav.find_session) + page.should have_no_selector("#sessions-scheduled .rsvp-msg span.text a.start", text: "Start session now?") + fast_signout + + # RSVP user + fast_signin(@rsvp_user, Nav.find_session) + page.should have_no_selector("#sessions-scheduled .rsvp-msg span.text a.start", text: "Start session now?") + page.should have_selector("#sessions-scheduled .rsvp-msg span.text a.cancel", text: "Cancel RSVP") + fast_signout + + # now approve the RSVP + @rsvp_request.rsvp_requests_rsvp_slots[0].chosen = true + @rsvp_request.rsvp_requests_rsvp_slots[0].save! + + # "start session" should still be hidden + fast_signin(@rsvp_user, Nav.find_session) + page.should have_no_selector("#sessions-scheduled .rsvp-msg span.text a.start", text: "Start session now?") + page.should have_selector("#sessions-scheduled .rsvp-msg span.text a.cancel", text: "Cancel RSVP") + fast_signout + end + end + describe "rsvp behavior" do before(:each) do stub_const("APP_CONFIG", web_config) @@ -222,10 +336,9 @@ describe "Find Session", :js => true, :type => :feature, :capybara_feature => tr it "RSVP text shows correctly" do music_session = FactoryGirl.create(:music_session, creator: user) + # session creator cannot cancel fast_signin(user, Nav.find_session) - - find("#sessions-scheduled .rsvp-msg span.text", text: "You have been confirmed for this session. ") - + page.should have_no_selector("#sessions-scheduled .rsvp-msg span.text a.cancel", text: "Cancel RSVP") sign_out # create a slot so the session can be joined @@ -241,15 +354,15 @@ describe "Find Session", :js => true, :type => :feature, :capybara_feature => tr # first state: an unconfirmed RSVP go_to_root fast_signin(finder, Nav.find_session) - find("#sessions-scheduled .rsvp-msg span.text", text: "You have RSVP'ed to this session. ") + find("#sessions-scheduled .rsvp-msg span.text a.cancel", text: "Cancel RSVP") rsvp_request.rsvp_requests_rsvp_slots[0].chosen = true rsvp_request.rsvp_requests_rsvp_slots[0].save! - # second state: a connfirmed RSVP + # second state: a confirmed RSVP go_to_root fast_signin(finder, Nav.find_session) - find("#sessions-scheduled .rsvp-msg span.text", text: "You have been confirmed for this session. ") + find("#sessions-scheduled a.cancel", text: "Cancel RSVP") # need to now CANCEL, and check what it says: // VRFS-1891 diff --git a/web/spec/features/oauth_spec.rb b/web/spec/features/oauth_spec.rb index 024418400..a24e6cfae 100644 --- a/web/spec/features/oauth_spec.rb +++ b/web/spec/features/oauth_spec.rb @@ -1,5 +1,5 @@ require 'spec_helper' -require 'you_tube_client' +require 'google_client' describe "OAuth", :slow=>true, :js=>true, :type=>:feature, :capybara_feature=>true do @@ -15,7 +15,7 @@ describe "OAuth", :slow=>true, :js=>true, :type=>:feature, :capybara_feature=>tr end before(:each) do - @youtube_client = YouTubeClient.new() + @youtube_client = GoogleClient.new() end after(:each) do diff --git a/web/spec/features/session_start_dialog_spec.rb b/web/spec/features/session_start_dialog_spec.rb new file mode 100644 index 000000000..e69de29bb diff --git a/web/spec/features/youtube_spec.rb b/web/spec/features/youtube_spec.rb index 48d905df3..1fe81bf06 100644 --- a/web/spec/features/youtube_spec.rb +++ b/web/spec/features/youtube_spec.rb @@ -1,5 +1,5 @@ require 'spec_helper' -require 'you_tube_client' +require 'google_client' require 'rest_client' describe "YouTube", :slow=>true, :js=>true, :type => :feature, :capybara_feature => true do @@ -12,7 +12,7 @@ describe "YouTube", :slow=>true, :js=>true, :type => :feature, :capybara_feature @previous_run_server = Capybara.run_server Capybara.run_server = false @user=FactoryGirl.create(:user, :email => "jamkazamtest@gmail.com") - @youtube_client = YouTubeClient.new() + @youtube_client = GoogleClient.new() authorize_google_user(@youtube_client, @user, "stinkyblueberryjam") google_auth = UserAuthorization.google_auth(@user).first # Consider returning this from above now that it is reliable end @@ -25,7 +25,7 @@ describe "YouTube", :slow=>true, :js=>true, :type => :feature, :capybara_feature it "should retrieve upload url" do length = 3276 - upload_hash=@youtube_client.upload_sign(@user, "test_video.mp4", length) + upload_hash=@youtube_client.sign_youtube_upload(@user, "test_video.mp4", length) upload_hash.should_not be_nil upload_hash.length.should be >=1 upload_hash['method'].should eq("PUT") @@ -35,13 +35,13 @@ describe "YouTube", :slow=>true, :js=>true, :type => :feature, :capybara_feature upload_hash['Content-Length'].should eq(length) upload_hash['Content-Type'].should_not be_nil - @youtube_client.verify_upload(@user, upload_hash['url'], length).should be_false + @youtube_client.verify_youtube_upload(@user, upload_hash['url'], length).should be_false end it "upload url should allow uploading" do vid_path = Rails.root.join('spec', 'files', 'test_video.mp4') length = File.size?(vid_path) - upload_hash=@youtube_client.upload_sign(@user, "test_video.mp4", length) + upload_hash=@youtube_client.sign_youtube_upload(@user, "test_video.mp4", length) #puts upload_hash.inspect upload_hash.should_not be_nil upload_hash.length.should be >=1 @@ -54,8 +54,8 @@ describe "YouTube", :slow=>true, :js=>true, :type => :feature, :capybara_feature # Upload this file as the client would: RestClient.put(upload_hash['url'], File.read(vid_path)) - @youtube_client.verify_upload(@user, upload_hash['url'], length).should be_true - #@youtube_client.get_upload_status(@user, upload_hash['url'], length) + @youtube_client.verify_youtube_upload(@user, upload_hash['url'], length).should be_true + #@youtube_client.youtube_upload_status(@user, upload_hash['url'], length) end it "sets upload flag when complete" do @@ -67,7 +67,7 @@ describe "YouTube", :slow=>true, :js=>true, :type => :feature, :capybara_feature vid_path = Rails.root.join('spec', 'files', 'test_video.mp4') length = File.size?(vid_path) - upload_hash=@youtube_client.upload_sign(@user, "test_video.mp4", length) + upload_hash=@youtube_client.sign_youtube_upload(@user, "test_video.mp4", length) upload_hash.should_not be_nil upload_hash['url'].should_not be_nil RestClient.put(upload_hash['url'], File.read(vid_path)) @@ -82,7 +82,7 @@ describe "YouTube", :slow=>true, :js=>true, :type => :feature, :capybara_feature @recording.recorded_videos << recorded_video - @youtube_client.verify_upload(@user, upload_hash['url'], length).should be_true + @youtube_client.verify_youtube_upload(@user, upload_hash['url'], length).should be_true @youtube_client.complete_upload(recorded_video).should be_true recorded_video.fully_uploaded.should be_true end diff --git a/web/spec/managers/user_manager_spec.rb b/web/spec/managers/user_manager_spec.rb index 23368a208..275d90b69 100644 --- a/web/spec/managers/user_manager_spec.rb +++ b/web/spec/managers/user_manager_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' describe UserManager do before(:each) do + Rails.application.config.recaptcha_enable=false @user_manager = UserManager.new(:conn => @conn) UserMailer.deliveries.clear @location = { :country => "US", :state => "Arkansas", :city => "Little Rock" } @@ -662,12 +663,13 @@ describe UserManager do end # describe "without nocaptcha" describe "with nocaptcha" do - before(:all) do + before(:each) do @old_recaptcha=Rails.application.config.recaptcha_enable Rails.application.config.recaptcha_enable=true + UserMailer.deliveries.clear end - after(:all) do + after(:each) do Rails.application.config.recaptcha_enable=@old_recaptcha end @@ -682,11 +684,14 @@ describe UserManager do instruments: @instruments, musician: true, location: @loca, - recaptcha_failed: true, + recaptcha_response: nil, signup_confirm_url: "http://localhost:3000/confirm") user.errors.any?.should be_true + UserMailer.deliveries.should have(0).items + end + it "passes when facebook signup" do user = @user_manager.signup(remote_ip: "1.2.3.4", first_name: "bob", last_name: "smith", @@ -694,13 +699,14 @@ describe UserManager do password: "foobar", password_confirmation: "foobar", terms_of_service: true, - recaptcha_failed: false, + fb_signup: FactoryGirl.create(:facebook_signup), + recaptcha_response: nil, instruments: @instruments, musician: true, location: @loca, signup_confirm_url: "http://localhost:3000/confirm") user.errors.any?.should be_false - end # it "fails when nocaptcha fails" + end # it "passes when facebook signup" end # describe "with nocaptcha" end # test diff --git a/web/spec/testing_oauth.txt b/web/spec/testing_oauth.txt index db139b81f..2a6ad3874 100644 --- a/web/spec/testing_oauth.txt +++ b/web/spec/testing_oauth.txt @@ -4,7 +4,7 @@ To obtain an access token, one must actually log into google using a browser run Getting an access token for the purposes of automated testing is tricky, but possible using Capybara with a javascript-enabled driver. (Note, web/spec/support/utilities.rb utilizes the JK youtube client to perform the intricate bits): -1) Obtain the login URL. It's ugly, but we can get it from the YouTubeClient. It contains the callback URL, as well as a "hint" that will fill in the username for us. +1) Obtain the login URL. It's ugly, but we can get it from the GoogleClient. It contains the callback URL, as well as a "hint" that will fill in the username for us. 2) Start a web server on an enabled callback server, such as localhost:3000 3) Obtain the URL using a known test user 4) Visit the URL in a capybara test @@ -12,7 +12,7 @@ Getting an access token for the purposes of automated testing is tricky, but pos 4b) Click the login button 4c) The approve page should load. Wait for the approve button to be enabled. This is usually a second or two after the page loads, but not immediately. 4d) Click the approve button -5) After google approves, some javascript will redirect to our test web server, which contains a code. This is not the access_token, but a one-time code that can be exchanged for an access_token, again POSTing to google's auth server. You can see it in gory detail in YouTubeClient.exchange_for_token. +5) After google approves, some javascript will redirect to our test web server, which contains a code. This is not the access_token, but a one-time code that can be exchanged for an access_token, again POSTing to google's auth server. You can see it in gory detail in GoogleClient.exchange_for_token. 6) If all goes well, the test web server will call back the invoker with a real access token. 7) For testing purposes, stick the access token in the user.user_authorizations table for the user for which we are testing. diff --git a/websocket-gateway/lib/jam_websockets/router.rb b/websocket-gateway/lib/jam_websockets/router.rb index 459b59bec..cf00b389b 100644 --- a/websocket-gateway/lib/jam_websockets/router.rb +++ b/websocket-gateway/lib/jam_websockets/router.rb @@ -804,7 +804,7 @@ module JamWebsockets id = subscribe.id type = subscribe.type if id && id.length > 0 && type && type.length > 0 - register_subscription(client, type, id) + #register_subscription(client, type, id) else @log.error("handle_subscribe: empty data #{subscribe}") end @@ -814,7 +814,7 @@ module JamWebsockets id = unsubscribe.id type = unsubscribe.type if id && id.length > 0 && type && type.length > 0 - unregister_subscription(client, type, id) + #unregister_subscription(client, type, id) else @log.error("handle_subscribe: empty data #{unsubscribe}") end