session limits done
This commit is contained in:
parent
9da0b37aeb
commit
ce301fd145
|
|
@ -96,6 +96,7 @@ ALTER TABLE arses ADD COLUMN continent VARCHAR(200);
|
|||
ALTER TABLE users ADD COLUMN recurly_subscription_id VARCHAR(100) DEFAULT NULL;
|
||||
ALTER TABLE users ADD COLUMN recurly_token VARCHAR(200) DEFAULT NULL;
|
||||
ALTER TABLE users ADD COLUMN recurly_subscription_state VARCHAR(20) DEFAULT NULL;
|
||||
ALTER TABLE users ADD COLUMN subscription_plan_code VARCHAR(100) DEFAULT NULL;
|
||||
CREATE TABLE subscriptions (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
name VARCHAR(200) UNIQUE NOT NULL UNIQUE NOT NULL,
|
||||
|
|
@ -113,3 +114,12 @@ CREATE TABLE subscriptions (
|
|||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
ALTER TABLE users ADD COLUMN subscription_trial_ends_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||
ALTER TABLE users ADD COLUMN subscription_plan_reason varchar(20);
|
||||
|
||||
CREATE INDEX msuh_user_id ON music_sessions_user_history((1)) WHERE is_a_student;
|
||||
|
||||
-- alreday on WWW
|
||||
CREATE INDEX msuh_user_id ON music_sessions_user_history USING btree (user_id);
|
||||
CREATE INDEX msuh_created_at ON music_sessions_user_history USING btree (created_at);
|
||||
|
|
@ -54,6 +54,10 @@ message ClientMessage {
|
|||
SCHEDULED_SESSION_RESCHEDULED = 180;
|
||||
SCHEDULED_SESSION_REMINDER = 181;
|
||||
SCHEDULED_SESSION_COMMENT = 182;
|
||||
SESSION_KICK = 183;
|
||||
|
||||
// subscription-related
|
||||
SUBSCRIPTION_CHANGED = 195;
|
||||
|
||||
// recording notifications
|
||||
MUSICIAN_RECORDING_SAVED = 200;
|
||||
|
|
@ -177,6 +181,10 @@ message ClientMessage {
|
|||
optional ScheduledSessionRescheduled scheduled_session_rescheduled = 180;
|
||||
optional ScheduledSessionReminder scheduled_session_reminder = 181;
|
||||
optional ScheduledSessionComment scheduled_session_comment = 182;
|
||||
optional SessionKick session_kick = 183;
|
||||
|
||||
// subscription-related
|
||||
optional SubscriptionChanged subscription_changed = 195;
|
||||
|
||||
// recording notifications
|
||||
optional MusicianRecordingSaved musician_recording_saved = 200;
|
||||
|
|
@ -528,6 +536,15 @@ message ScheduledSessionComment {
|
|||
optional string created_at = 8;
|
||||
}
|
||||
|
||||
message SessionKick {
|
||||
optional string session_id = 1;
|
||||
optional string reason = 2;
|
||||
}
|
||||
|
||||
message SubscriptionChanged {
|
||||
|
||||
}
|
||||
|
||||
message MusicianRecordingSaved {
|
||||
optional string recording_id = 1;
|
||||
optional string photo_url = 2;
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ require "jam_ruby/lib/em_helper"
|
|||
require "jam_ruby/lib/nav"
|
||||
require "jam_ruby/lib/html_sanitize"
|
||||
require "jam_ruby/lib/guitar_center"
|
||||
require "jam_ruby/subscription_definitions"
|
||||
require "jam_ruby/resque/resque_jam_error"
|
||||
require "jam_ruby/resque/resque_hooks"
|
||||
require "jam_ruby/resque/audiomixer"
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ SQL
|
|||
end
|
||||
end
|
||||
|
||||
def update_session_controller(music_session_id)
|
||||
def update_session_controller(music_session_id, kick_extras = false)
|
||||
tracks_changed = false
|
||||
active_music_session = ActiveMusicSession.find(music_session_id)
|
||||
|
||||
|
|
@ -362,7 +362,22 @@ SQL
|
|||
# find next in line, because the current 'session controller' is not part of the session
|
||||
tracks_changed = next_in_line(music_session, active_music_session)
|
||||
end
|
||||
|
||||
|
||||
if kick_extras
|
||||
num_participants = active_music_session.users.count
|
||||
|
||||
puts("kick extras = num_participants #{num_participants}")
|
||||
active_music_session.users.each do |user|
|
||||
subscription_rules = user.subscription_rules(false)
|
||||
puts "checking max players for #{user.email} #{subscription_rules[:max_players]}"
|
||||
if subscription_rules[:max_players] && subscription_rules[:max_players] < num_participants
|
||||
puts "kicking user #{user.email}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
tracks_changed
|
||||
end
|
||||
|
||||
|
|
@ -436,7 +451,8 @@ SQL
|
|||
if connection.errors.any?
|
||||
raise ActiveRecord::Rollback
|
||||
else
|
||||
tracks_changed = update_session_controller(music_session.id)
|
||||
tracks_changed = update_session_controller(music_session.id, kick_extras = true)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ module ValidationMessages
|
|||
CAN_ONLY_JOIN_SAME_SCHOOL_SESSION = "You can only join sessions from your school"
|
||||
LICENSE_EXPIRED = "Your license has expired"
|
||||
LICENSE_NOT_STARTED = "Your license has not started"
|
||||
PLAN_PROHIBIT_MAX_PLAYERS = "The session size is greater than your plan allows"
|
||||
|
||||
# chat
|
||||
CAN_ONLY_CHAT_SAME_SCHOOL = "You can only message others from your school"
|
||||
|
|
|
|||
|
|
@ -936,6 +936,16 @@ module JamRuby
|
|||
self.save
|
||||
end
|
||||
|
||||
def play_time_remaining(user)
|
||||
rules = SubscriptionDefinitions.rules(user.subscription_plan_code)
|
||||
play_time_per_session = rules[:play_time_per_session]
|
||||
if play_time_per_session.nil?
|
||||
nil
|
||||
else
|
||||
(play_time_per_session * 3600) - MusicSessionUserHistory.where(music_session_id: self.id).where(user_id: user.id).sum("extract('epoch' from (COALESCE(session_removed_at, NOW()) - created_at))")
|
||||
end
|
||||
end
|
||||
|
||||
def self.sync(session_history)
|
||||
music_session = MusicSession.find_by_id(session_history.id)
|
||||
|
||||
|
|
|
|||
|
|
@ -166,6 +166,18 @@ module JamRuby
|
|||
errors.add(:music_session, ValidationMessages::LICENSE_NOT_STARTED)
|
||||
end
|
||||
|
||||
num_participants = music_session.users.count
|
||||
|
||||
puts "NUM PARTICIPANTS BEFORE JOIN #{num_participants}"
|
||||
subscription_rules = self.user.subscription_rules(dynamic_definitions = false)
|
||||
|
||||
max_players = subscription_rules[:max_players]
|
||||
if !max_players.nil?
|
||||
if num_participants >= max_players
|
||||
errors.add(:music_session, ValidationMessages::PLAN_PROHIBIT_MAX_PLAYERS)
|
||||
end
|
||||
end
|
||||
|
||||
# unless user.admin?
|
||||
# num_sessions = Connection.where(:user_id => user_id)
|
||||
# .where(["(music_session_id IS NOT NULL) AND (aasm_state != ?)",EXPIRED_STATE.to_s])
|
||||
|
|
|
|||
|
|
@ -274,7 +274,10 @@ module JamRuby
|
|||
if sale.valid?
|
||||
|
||||
client = RecurlyClient.new
|
||||
account = client.get_account(current_user)
|
||||
|
||||
account = client.find_or_create_account(current_user, nil, recurly_token)
|
||||
|
||||
client.update_billing_info_from_token(current_user, account, recurly_token)
|
||||
|
||||
if account.present?
|
||||
recurly_response = client.create_subscription(current_user, plan_code, account)
|
||||
|
|
@ -288,6 +291,7 @@ module JamRuby
|
|||
sale.recurly_currency = recurly_response.currency
|
||||
sale.save(validate: false)
|
||||
else
|
||||
puts "Could not find account to place order."
|
||||
raise RecurlyClientError, "Could not find account to place order."
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ module JamRuby
|
|||
def product
|
||||
if product_type == JAMTRACK
|
||||
JamTrack.find_by_id(product_id)
|
||||
if product_type == SUBSCRIPTION
|
||||
elsif product_type == SUBSCRIPTION
|
||||
{name: product_id}
|
||||
elsif product_type == GIFTCARD
|
||||
GiftCardType.find_by_id(product_id)
|
||||
|
|
|
|||
|
|
@ -2814,6 +2814,21 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
def subscription_rules(dynamic_definitions = true)
|
||||
rules = SubscriptionDefinitions.rules(self.subscription_plan_code)
|
||||
if dynamic_definitions
|
||||
play_time_per_month = rules[:play_time_per_month]
|
||||
if play_time_per_month.nil?
|
||||
rules[:remaining_month_play_time] = nil
|
||||
else
|
||||
rules[:remaining_month_play_time] = (play_time_per_month * 3600) - MusicSessionUserHistory.where(user_id: self.id).where("date_trunc('month', created_at) = date_trunc('month', NOW())").where('session_removed_at IS NOT NULL').sum("extract('epoch' from (session_removed_at - created_at))")
|
||||
end
|
||||
end
|
||||
|
||||
rules
|
||||
end
|
||||
|
||||
private
|
||||
def create_remember_token
|
||||
self.remember_token = SecureRandom.urlsafe_base64
|
||||
|
|
|
|||
|
|
@ -11,9 +11,11 @@ module JamRuby
|
|||
begin
|
||||
#puts "Recurly.api_key: #{Recurly.api_key}"
|
||||
account = Recurly::Account.create(options)
|
||||
raise RecurlyClientError.new(account.errors) if account.errors.any?
|
||||
if account.errors.any?
|
||||
puts "Errors encountered while creating account: #{account.errors}"
|
||||
raise RecurlyClientError.new(account.errors) if account.errors.any?
|
||||
end
|
||||
rescue Recurly::Error, NoMethodError => x
|
||||
#puts "Error: #{x} : #{Kernel.caller}"
|
||||
raise RecurlyClientError, x.to_s
|
||||
else
|
||||
if account
|
||||
|
|
@ -30,7 +32,7 @@ module JamRuby
|
|||
|
||||
def delete_account(current_user)
|
||||
account = get_account(current_user)
|
||||
if (account)
|
||||
if account
|
||||
begin
|
||||
account.destroy
|
||||
rescue Recurly::Error, NoMethodError => x
|
||||
|
|
@ -43,11 +45,26 @@ module JamRuby
|
|||
end
|
||||
|
||||
def get_account(current_user)
|
||||
current_user && current_user.recurly_code ? Recurly::Account.find(current_user.recurly_code) : nil
|
||||
account = current_user && current_user.recurly_code ? Recurly::Account.find(current_user.recurly_code) : nil
|
||||
|
||||
# check again, assuming account_code is the user ID (can happen in error scenarios where we create the account
|
||||
# on recurly, but couldn't save the account_code to the user.recurly_code field)
|
||||
|
||||
if !account
|
||||
account = Recurly::Account.find(current_user.id)
|
||||
# repair user local account info
|
||||
if !account.nil?
|
||||
current_user.update_attribute(:recurly_code, account.account_code)
|
||||
end
|
||||
end
|
||||
|
||||
account
|
||||
|
||||
rescue Recurly::Error => x
|
||||
raise RecurlyClientError, x.to_s
|
||||
end
|
||||
|
||||
|
||||
def update_account(current_user, billing_info=nil)
|
||||
account = get_account(current_user)
|
||||
if(account.present?)
|
||||
|
|
@ -94,9 +111,9 @@ module JamRuby
|
|||
payments
|
||||
end
|
||||
|
||||
def update_billing_info(current_user, billing_info=nil)
|
||||
account = get_account(current_user)
|
||||
if (account.present?)
|
||||
def update_billing_info(current_user, billing_info=nil, account = nil)
|
||||
account = get_account(current_user) if account.nil?
|
||||
if account.present?
|
||||
begin
|
||||
account.billing_info = billing_info
|
||||
account.billing_info.save
|
||||
|
|
@ -111,6 +128,14 @@ module JamRuby
|
|||
account
|
||||
end
|
||||
|
||||
# token was created in the web ui. we can tell recurly to update the billing info on the account with just the token
|
||||
def update_billing_info_from_token(current_user, account, recurly_token)
|
||||
account.billing_info = {
|
||||
token_id: recurly_token
|
||||
}
|
||||
account.billing_info.save!
|
||||
end
|
||||
|
||||
def refund_user_subscription(current_user, jam_track)
|
||||
jam_track_right=JamRuby::JamTrackRight.where("user_id=? AND jam_track_id=?", current_user.id, jam_track.id).first
|
||||
if jam_track_right
|
||||
|
|
@ -188,6 +213,7 @@ module JamRuby
|
|||
|
||||
# https://dev.recurly.com/docs/create-subscription
|
||||
def create_subscription(user, plan_code, account)
|
||||
puts "Creating subscription for #{user.email} with plan_code #{plan_code}"
|
||||
subscription = Recurly::Subscription.create(
|
||||
:plan_code => plan_code,
|
||||
:currency => 'USD',
|
||||
|
|
@ -200,14 +226,58 @@ module JamRuby
|
|||
subscription
|
||||
end
|
||||
|
||||
def find_subscription(user)
|
||||
def find_subscription(user, account = nil)
|
||||
subscription = nil
|
||||
|
||||
if user.recurly_subscription_id.nil?
|
||||
nil
|
||||
if account.nil?
|
||||
account = get_account(user)
|
||||
end
|
||||
if account
|
||||
account.subscriptions.find_each do |subscription|
|
||||
puts "Subscription: #{subscription.inspect}"
|
||||
end
|
||||
subscription = account.subscriptions.first
|
||||
else
|
||||
puts "can't find subscription for account #{account}"
|
||||
end
|
||||
else
|
||||
Recurly::Subscription.find(user.recurly_subscription_id)
|
||||
subscription = Recurly::Subscription.find(user.recurly_subscription_id)
|
||||
end
|
||||
|
||||
if user.recurly_subscription_id.nil?
|
||||
puts "Repairing subscription ID on account"
|
||||
user.update_attribute(:recurly_subscription_id, subscription.id)
|
||||
user.recurly_subscription_id = subscription.id
|
||||
end
|
||||
|
||||
subscription
|
||||
end
|
||||
|
||||
def change_subscription_plan(current_user, plan_code)
|
||||
subscription = find_subscription(current_user)
|
||||
|
||||
if subscription.nil?
|
||||
puts "no subscription found for user #{current_user.email}"
|
||||
return false
|
||||
end
|
||||
|
||||
puts "subscription.plan #{subscription.plan}"
|
||||
if subscription.plan.plan_code == plan_code
|
||||
puts "plan code was the same as requested: #{plan_code}"
|
||||
return false
|
||||
end
|
||||
|
||||
result = subscription.update_attributes(
|
||||
:plan_code => plan_code,
|
||||
:timeframe => 'bill_date'
|
||||
)
|
||||
puts "change subscription plan #{result}"
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
|
||||
def sync_subscription(user)
|
||||
subscription = find_subscription(user)
|
||||
|
||||
|
|
@ -225,13 +295,17 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
def find_or_create_account(current_user, billing_info)
|
||||
def find_or_create_account(current_user, billing_info, recurly_token = nil)
|
||||
account = get_account(current_user)
|
||||
|
||||
if(account.nil?)
|
||||
if !account
|
||||
account = create_account(current_user, billing_info)
|
||||
else
|
||||
update_billing_info(current_user, billing_info)
|
||||
elsif !billing_info.nil?
|
||||
update_billing_info(current_user, billing_info, account)
|
||||
end
|
||||
|
||||
if !recurly_token.nil?
|
||||
update_billing_info_from_token(current_user, account, recurly_token)
|
||||
end
|
||||
account
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
module JamRuby
|
||||
class SubscriptionDefinitions
|
||||
JAM_SILVER = 'jamsubsilver'
|
||||
JAM_SILVER_WITH_TRIAL = 'jamsubsilvertrial'
|
||||
JAM_GOLD = 'jamsubgold'
|
||||
JAM_GOLD_WITH_TRIAL = 'jamsubgoldtrial'
|
||||
JAM_PLATINUM = 'jamsubplatinum'
|
||||
JAM_PLATINUM_WITH_TRIAL = 'jamsubplatinumtrial'
|
||||
|
||||
# ALL IN HOURS
|
||||
FREE_PLAY_TIME_PER_SESSION = 1
|
||||
FREE_PLAY_TIME_PER_MONTH = 4
|
||||
SILVER_PLAY_TIME_PER_SESSION = nil # unlimited
|
||||
SILVER_PLAY_TIME_PER_MONTH = 10
|
||||
GOLD_PLAY_TIME_PER_SESSION = nil # unlimited
|
||||
GOLD_PLAY_TIME_PER_MONTH = nil # unlimited
|
||||
PLATINUM_PLAY_TIME_PER_SESSION = nil # unlimited
|
||||
PLATINUM_PLAY_TIME_PER_MONTH = nil # unlimited
|
||||
|
||||
|
||||
FREE_PLAN = {
|
||||
play_time_per_month: FREE_PLAY_TIME_PER_MONTH,
|
||||
play_time_per_session: FREE_PLAY_TIME_PER_SESSION,
|
||||
recording: false,
|
||||
video: 'no',
|
||||
audio_bitrate: '128',
|
||||
broadcasting: 'no',
|
||||
max_players: 4
|
||||
|
||||
}
|
||||
|
||||
SILVER_PLAN = {
|
||||
play_time_per_month: SILVER_PLAY_TIME_PER_MONTH,
|
||||
play_time_per_session: SILVER_PLAY_TIME_PER_SESSION,
|
||||
recording: false,
|
||||
video: 'cif',
|
||||
audio_bitrate: '192',
|
||||
broadcasting: 'free',
|
||||
max_players: 6
|
||||
}
|
||||
|
||||
GOLD_PLAN = {
|
||||
play_time_per_month: GOLD_PLAY_TIME_PER_MONTH,
|
||||
play_time_per_session: GOLD_PLAY_TIME_PER_SESSION,
|
||||
recording: true,
|
||||
video: '720p',
|
||||
audio_bitrate: '256',
|
||||
broadcasting: 'free',
|
||||
max_players: nil
|
||||
}
|
||||
|
||||
PLATINUM_PLAN = {
|
||||
play_time_per_month: PLATINUM_PLAY_TIME_PER_MONTH,
|
||||
play_time_per_session: PLATINUM_PLAY_TIME_PER_SESSION,
|
||||
recording: true,
|
||||
video: '1080p',
|
||||
audio_bitrate: '512',
|
||||
broadcasting: 'busking',
|
||||
max_players: nil
|
||||
}
|
||||
|
||||
def self.rules(plan_code)
|
||||
if plan_code == nil
|
||||
FREE_PLAN
|
||||
elsif plan_code == JAM_SILVER || plan_code == JAM_SILVER_WITH_TRIAL
|
||||
SILVER_PLAN
|
||||
elsif plan_code == JAM_GOLD || plan_code == JAM_GOLD_WITH_TRIAL
|
||||
GOLD_PLAN
|
||||
elsif plan_code == JAM_PLATINUM || plan_code == JAM_PLATINUM_WITH_TRIAL
|
||||
PLATINUM_PLAN
|
||||
else
|
||||
raise "unknown plan #{plan_code}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -105,7 +105,7 @@ gem 'rubyzip'
|
|||
gem 'slim'
|
||||
gem 'htmlentities'
|
||||
gem 'sanitize'
|
||||
gem 'recurly'
|
||||
gem 'recurly', '~> 2'
|
||||
#gem 'guard', '2.7.3'
|
||||
#gem 'influxdb' #, '0.1.8'
|
||||
gem 'cause' # needed by influxdb
|
||||
|
|
@ -167,7 +167,7 @@ end
|
|||
gem 'sass-rails'
|
||||
gem 'coffee-rails'
|
||||
gem 'uglifier'
|
||||
gem 'coffee-script-source', '1.11.1'
|
||||
gem 'coffee-script-source', '1.12.2'
|
||||
group :test, :cucumber do
|
||||
gem 'simplecov', '~> 0.7.1'
|
||||
gem 'simplecov-rcov'
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ GEM
|
|||
coffee-script (2.4.1)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.11.1)
|
||||
coffee-script-source (1.12.2)
|
||||
concurrent-ruby (1.0.5)
|
||||
connection_pool (2.2.1)
|
||||
crass (1.0.2)
|
||||
|
|
@ -577,7 +577,7 @@ GEM
|
|||
execjs
|
||||
rails (>= 3.2)
|
||||
tilt
|
||||
recurly (2.10.0)
|
||||
recurly (2.18.16)
|
||||
redis (3.3.3)
|
||||
redis-namespace (1.5.3)
|
||||
redis (~> 3.0, >= 3.0.4)
|
||||
|
|
@ -764,7 +764,7 @@ DEPENDENCIES
|
|||
carrierwave_direct
|
||||
cause
|
||||
coffee-rails
|
||||
coffee-script-source (= 1.11.1)
|
||||
coffee-script-source (= 1.12.2)
|
||||
database_cleaner (= 1.3.0)
|
||||
devise (= 3.3.0)
|
||||
em-websocket (>= 0.4.0)
|
||||
|
|
@ -826,7 +826,7 @@ DEPENDENCIES
|
|||
rails-observers
|
||||
railties (> 4.2)
|
||||
react-rails (= 1.3.3)
|
||||
recurly
|
||||
recurly (~> 2)
|
||||
responders (~> 2.0)
|
||||
resque
|
||||
resque-dynamic-queues
|
||||
|
|
|
|||
|
|
@ -175,11 +175,17 @@
|
|||
}
|
||||
else {
|
||||
$btn.click(function() {
|
||||
var hideOnClick = true
|
||||
if (button.click) {
|
||||
button.click();
|
||||
var result = button.click();
|
||||
if(result === 'noclose') {
|
||||
hideOnClick = false
|
||||
}
|
||||
}
|
||||
|
||||
hide();
|
||||
if(hideOnClick) {
|
||||
hide();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -182,6 +182,14 @@
|
|||
videoShared = true;
|
||||
}
|
||||
|
||||
function IsVstLoaded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function hasVstAssignment() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function FTUEGetInputLatency() {
|
||||
dbg("FTUEGetInputLatency");
|
||||
return 2;
|
||||
|
|
@ -793,6 +801,10 @@
|
|||
logger.debug("Fake JamClient: SessionAudioResync()");
|
||||
}
|
||||
|
||||
function getConnectionDetail(arg1, arg2) {
|
||||
return {}
|
||||
}
|
||||
|
||||
function SessionGetAllControlState(isMasterOrPersonal) {
|
||||
var mixerIds = SessionGetIDs()
|
||||
return SessionGetControlState(mixerIds, isMasterOrPersonal);
|
||||
|
|
@ -1651,6 +1663,7 @@
|
|||
this.SessionSetMasterLocalMix = SessionSetMasterLocalMix;
|
||||
this.SessionGetDeviceLatency = SessionGetDeviceLatency;
|
||||
this.SessionAudioResync = SessionAudioResync;
|
||||
this.getConnectionDetail = getConnectionDetail;
|
||||
|
||||
// Track
|
||||
this.TrackGetChannels = TrackGetChannels;
|
||||
|
|
@ -1751,7 +1764,10 @@
|
|||
this.FTUEGetVideoShareEnable = FTUEGetVideoShareEnable;
|
||||
this.isSessVideoShared = isSessVideoShared;
|
||||
this.SessStopVideoSharing = SessStopVideoSharing;
|
||||
this.SessStartVideoSharing = SessStartVideoSharing;
|
||||
this.SessStartVideoSharing = SessStartVideoSharing
|
||||
|
||||
this.IsVstLoaded = IsVstLoaded;
|
||||
this.hasVstAssignment = hasVstAssignment;
|
||||
|
||||
// Clipboard
|
||||
this.SaveToClipboard = SaveToClipboard;
|
||||
|
|
|
|||
|
|
@ -2802,6 +2802,48 @@
|
|||
})
|
||||
}
|
||||
|
||||
function createSubscription(options) {
|
||||
options = options || {}
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
url: '/api/recurly/create_subscription',
|
||||
dataType: "json",
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(options)
|
||||
})
|
||||
}
|
||||
|
||||
function getSubscription() {
|
||||
return $.ajax({
|
||||
type: "GET",
|
||||
url: '/api/recurly/get_subscription',
|
||||
dataType: "json",
|
||||
contentType: 'application/json'
|
||||
})
|
||||
}
|
||||
|
||||
function changeSubscription(options) {
|
||||
options = options || {}
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
url: '/api/recurly/change_subscription',
|
||||
dataType: "json",
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(options)
|
||||
})
|
||||
}
|
||||
|
||||
function cancelSubscription(options) {
|
||||
options = options || {}
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
url: '/api/recurly/cancel_subscription',
|
||||
dataType: "json",
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(options)
|
||||
})
|
||||
}
|
||||
|
||||
function createLiveStream(musicSessionId) {
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
|
|
@ -3128,6 +3170,10 @@
|
|||
this.findFriendSessions = findFriendSessions;
|
||||
this.findPublicSessions = findPublicSessions;
|
||||
this.getConfigClient = getConfigClient;
|
||||
this.createSubscription = createSubscription;
|
||||
this.getSubscription = getSubscription;
|
||||
this.changeSubscription = changeSubscription;
|
||||
this.cancelSubscription= cancelSubscription;
|
||||
return this;
|
||||
};
|
||||
})(window, jQuery);
|
||||
|
|
|
|||
|
|
@ -735,6 +735,34 @@
|
|||
//decrementNotificationCount();
|
||||
}
|
||||
|
||||
function registerSessionKick() {
|
||||
context.JK.JamServer.registerMessageCallback(context.JK.MessageType.SESSION_KICK, function(header, payload) {
|
||||
logger.debug("Handling SESSION_KICK msg " + JSON.stringify(payload));
|
||||
|
||||
context.SessionAction.leaveSession({
|
||||
location: '/client#/home',
|
||||
})
|
||||
|
||||
var buttons = []
|
||||
buttons.push({name: 'CLOSE', buttonStyle: 'button-grey'})
|
||||
buttons.push({name: 'COMPARE PLANS', buttonStyle: 'button-grey', click: function() {
|
||||
context.JK.popExternalLink("https://jamkazam.freshdesk.com/support/solutions/articles/66000122535-what-are-jamkazam-s-free-vs-premium-features-")
|
||||
return 'noclose'
|
||||
}})
|
||||
buttons.push({
|
||||
name: 'UPGRADE PLAN',
|
||||
buttonStyle: 'button-orange',
|
||||
click: function() {
|
||||
context.JK.popExternalLink("/client#/account/subscription", true)
|
||||
}
|
||||
})
|
||||
context.JK.Banner.show({
|
||||
title: "Session Too Big For Current Plan",
|
||||
html: context._.template($('#template-session-too-big-kicked').html(), {}, { variable: 'data' }),
|
||||
buttons: buttons});
|
||||
})
|
||||
}
|
||||
|
||||
function registerSessionInvitation() {
|
||||
context.JK.JamServer.registerMessageCallback(context.JK.MessageType.SESSION_INVITATION, function(header, payload) {
|
||||
logger.debug("Handling SESSION_INVITATION msg " + JSON.stringify(payload));
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ logger = context.JK.logger
|
|||
|
||||
AppStore = context.AppStore
|
||||
UserStore = context.UserStore
|
||||
SubscriptionStore = context.SubscriptionStore
|
||||
SubscriptionActions = context.SubscriptionActions
|
||||
|
||||
profileUtils = context.JK.ProfileUtils
|
||||
|
||||
|
|
@ -12,7 +14,8 @@ profileUtils = context.JK.ProfileUtils
|
|||
mixins: [
|
||||
ICheckMixin,
|
||||
Reflux.listenTo(AppStore, "onAppInit"),
|
||||
Reflux.listenTo(UserStore, "onUserChanged")
|
||||
Reflux.listenTo(UserStore, "onUserChanged"),
|
||||
Reflux.listenTo(SubscriptionStore, "onSubscriptionChanged")
|
||||
]
|
||||
|
||||
onAppInit: (@app) ->
|
||||
|
|
@ -21,26 +24,22 @@ profileUtils = context.JK.ProfileUtils
|
|||
onUserChanged: (userState) ->
|
||||
@setState({user: userState?.user})
|
||||
|
||||
componentDidUpdate: () ->
|
||||
console.log("did update")
|
||||
|
||||
onSubscriptionChanged: (subscription) ->
|
||||
@setState({subscription: subscription})
|
||||
|
||||
beforeHide: (e) ->
|
||||
@screenVisible = false
|
||||
return true
|
||||
|
||||
beforeShow: (e) ->
|
||||
console.log("before show")
|
||||
SubscriptionActions.updateSubscription()
|
||||
|
||||
afterShow: (e) ->
|
||||
@screenVisible = true
|
||||
logger.debug("AccountSubscriptionScreen: afterShow")
|
||||
|
||||
getInitialState: () ->
|
||||
{
|
||||
user: null,
|
||||
updating: false
|
||||
}
|
||||
{ user: null, updating: false, subscription: null}
|
||||
|
||||
onCancel: (e) ->
|
||||
e.preventDefault()
|
||||
|
|
@ -48,15 +47,31 @@ profileUtils = context.JK.ProfileUtils
|
|||
|
||||
render: () ->
|
||||
|
||||
if @state.subscription
|
||||
|
||||
if @state.subscription.plan
|
||||
currentSubscription = `<CurrentSubscription subscription={this.state.subscription} />`
|
||||
|
||||
createSubscription = `<Subscription subscription={this.state.subscription}/>`
|
||||
content = `<div>
|
||||
<div className="current-subscription-block">
|
||||
{currentSubscription}
|
||||
</div>
|
||||
<div className="payment-block">
|
||||
{createSubscription}
|
||||
</div>
|
||||
</div>`
|
||||
else
|
||||
content = `<div className="loading">Loading...</div>`
|
||||
|
||||
`<div className="content-body-scroller">
|
||||
<div className="profile-header profile-head">
|
||||
<div className="store-header">subscription:</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className="profile-body">
|
||||
<div className="profile-wrapper">
|
||||
<div className="main-content">
|
||||
<Subscription />
|
||||
{content}
|
||||
<div className="actions">
|
||||
<a onClick={this.onCancel}>LEAVE</a>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
context = window
|
||||
rest = context.JK.Rest()
|
||||
logger = context.JK.logger
|
||||
LocationActions = context.LocationActions
|
||||
SubscriptionActions = context.SubscriptionActions
|
||||
UserStore = context.UserStore
|
||||
AppStore = context.AppStore
|
||||
|
||||
@CurrentSubscription = React.createClass({
|
||||
|
||||
mixins: [Reflux.listenTo(AppStore, "onAppInit")]
|
||||
|
||||
|
||||
getInitialState: () ->
|
||||
{
|
||||
selectedPlan: null
|
||||
}
|
||||
|
||||
getDisplayNameTier: (plan_code) ->
|
||||
for subscriptionCode in gon.global.subscription_codes
|
||||
if plan_code == subscriptionCode.id
|
||||
return subscriptionCode.name
|
||||
return "Unknown plan code=#{plan_code}"
|
||||
|
||||
getDisplayNamePrice: (plan_code) ->
|
||||
for subscriptionCode in gon.global.subscription_codes
|
||||
if plan_code == subscriptionCode.id
|
||||
return subscriptionCode.price
|
||||
return "Unknown plan code=#{plan_code}"
|
||||
|
||||
onPlanChanged: (e) ->
|
||||
val = $(e.target).val()
|
||||
@setState({selectedPlan: val})
|
||||
|
||||
currentPlan: () ->
|
||||
this.state.selectedPlan || this.props.selectedPlan || ''
|
||||
|
||||
onChangeSubmit: (event) ->
|
||||
form = event.target
|
||||
event.preventDefault()
|
||||
|
||||
if !@state.selectedPlan
|
||||
return
|
||||
SubscriptionActions.changeSubscription(this.state.selectedPlan)
|
||||
|
||||
onCancelPlan: (event) ->
|
||||
if confirm("Are you sure you want to cancel your plan?")
|
||||
SubscriptionActions.cancelSubscription()
|
||||
|
||||
componentDidMount: () ->
|
||||
|
||||
@root = $(@getDOMNode())
|
||||
|
||||
document.querySelector('#change-subscription-form').addEventListener('submit', @onChangeSubmit.bind(this))
|
||||
|
||||
render: () ->
|
||||
plan_codes = []
|
||||
for plan in gon.global.subscription_codes
|
||||
plan_codes.push(`<option key={plan.id} value={plan.id}>{plan.name} ({plan.price}/month)</option>`)
|
||||
|
||||
plansJsx = `
|
||||
<select name="plan_code" onChange={this.onPlanChanged} value={this.currentPlan()} >{plan_codes}</select>`
|
||||
|
||||
changeClass = 'button-orange'
|
||||
if !@state.selectedPlan
|
||||
changeClass = changeClass + ' disabled'
|
||||
|
||||
|
||||
if @props.subscription.pending_subscription
|
||||
currentPlan = this.getDisplayNameTier(this.props.subscription.pending_subscription.plan.plan_code)
|
||||
billingAddendum = `<span>(billed at {this.getDisplayNameTier(this.props.subscription.plan.plan_code)} until next billing cycle</span>`
|
||||
else
|
||||
currentPlan = this.getDisplayNameTier(this.props.subscription.plan.plan_code)
|
||||
billingAddendum = null
|
||||
`<div>
|
||||
<div>
|
||||
<h3>Current Subscription</h3>
|
||||
<div>
|
||||
{currentPlan}
|
||||
{billingAddendum}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3>Change Plan</h3>
|
||||
<form id="change-subscription-form">
|
||||
|
||||
<label for="plan_code">Change Plan To:</label>
|
||||
{plansJsx}
|
||||
|
||||
<button className={changeClass}>CHANGE PLAN</button>
|
||||
</form>
|
||||
</div>
|
||||
<div>
|
||||
<h3>Cancel Plan</h3>
|
||||
<button className="button-orange" onClick={this.onCancelPlan}>CANCEL PLAN</button>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
})
|
||||
|
|
@ -13,11 +13,13 @@ UserStore = context.UserStore
|
|||
getInitialState: () ->
|
||||
{
|
||||
clicked: false,
|
||||
selectedCountry: null
|
||||
selectedCountry: null,
|
||||
selectedPlan: null,
|
||||
subscription: null
|
||||
}
|
||||
|
||||
onLocationsChanged: (countries) ->
|
||||
console.log("countires in ", countries)
|
||||
console.log("countries in ", countries)
|
||||
@setState({countries: countries})
|
||||
|
||||
onCountryChanged: (e) ->
|
||||
|
|
@ -27,18 +29,26 @@ UserStore = context.UserStore
|
|||
currentCountry: () ->
|
||||
this.state.selectedCountry || this.props.selectedCountry || ''
|
||||
|
||||
onPlanChanged: (e) ->
|
||||
val = $(e.target).val()
|
||||
@setState({selectedPlan: val})
|
||||
|
||||
currentPlan: () ->
|
||||
this.state.selectedPlan || this.props.selectedPlan || ''
|
||||
|
||||
openBrowser: () ->
|
||||
context.JK.popExternalLink("https://www.jamkazam.com/client#/subscription")
|
||||
|
||||
onRecurlyToken: (err, token) ->
|
||||
console.log("TOKEN", token)
|
||||
onRecurlyToken: (err, token_data) ->
|
||||
|
||||
if err
|
||||
console.log("error", err)
|
||||
# handle error using err.code and err.fields
|
||||
else
|
||||
# recurly.js has filled in the 'token' field, so now we can submit the
|
||||
# form to your server
|
||||
console.log("eintercepted")
|
||||
console.log("eintercepted", token_data)
|
||||
rest.createSubscription({plan_code: @state.selectedPlan, recurly_token: token_data.id})
|
||||
|
||||
onFormSubmit: (event) ->
|
||||
form = event.target
|
||||
|
|
@ -51,6 +61,7 @@ UserStore = context.UserStore
|
|||
context.recurly.configure(gon.global.recurly_public_api_key)
|
||||
window.configuredRecurly = true
|
||||
|
||||
|
||||
componentDidMount: () ->
|
||||
LocationActions.load()
|
||||
|
||||
|
|
@ -100,7 +111,16 @@ UserStore = context.UserStore
|
|||
countryJsx = `
|
||||
<select name="countries" onChange={this.onCountryChanged} value={this.currentCountry()} data-recurly="country" autocomplete="shipping country">{countries}</select>`
|
||||
|
||||
`<form id="subscription-form">
|
||||
plan_codes = [`<option key='' value='' >Select Plan</option>`]
|
||||
for plan in gon.global.subscription_codes
|
||||
plan_codes.push(`<option key={plan.id} value={plan.id}>{plan.name} ({plan.price}/month)</option>`)
|
||||
|
||||
plansJsx = `
|
||||
<select name="plan_code" onChange={this.onPlanChanged} value={this.currentPlan()} >{plan_codes}</select>`
|
||||
|
||||
`<div>
|
||||
<h3>Update Payment</h3>
|
||||
<form id="subscription-form">
|
||||
<div id="subscription-account-data">
|
||||
<label for="first_name">First Name:</label>
|
||||
<input type="text" data-recurly="first_name" required autocomplete="cc-give-name"></input>
|
||||
|
|
@ -125,14 +145,16 @@ UserStore = context.UserStore
|
|||
|
||||
<label for="country">Country:</label>
|
||||
{countryJsx}
|
||||
<label for="plan_code">Plan:</label>
|
||||
{plansJsx}
|
||||
</div>
|
||||
<div id="subscription-elements">
|
||||
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="recurly-token" data-recurly="token"></input>
|
||||
|
||||
<button>submit</button>
|
||||
</form>`
|
||||
<button className="button-orange">SUBMIT</button>
|
||||
</form>
|
||||
</div>`
|
||||
|
||||
})
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
context = window
|
||||
|
||||
@SubscriptionConcern = React.createClass({
|
||||
displayName: 'SubscriptionConcern'
|
||||
|
||||
getTimeRemaining: (t) ->
|
||||
|
||||
if t < 0
|
||||
t = -t
|
||||
|
||||
seconds = Math.floor( (t/1000) % 60 );
|
||||
minutes = Math.floor( (t/1000/60) % 60 );
|
||||
hours = Math.floor( (t/(1000*60*60)) % 24 );
|
||||
days = Math.floor( t/(1000*60*60*24) );
|
||||
|
||||
return {
|
||||
'total': t,
|
||||
'days': days,
|
||||
'hours': hours,
|
||||
'minutes': minutes,
|
||||
'seconds': seconds
|
||||
};
|
||||
|
||||
|
||||
displayTime: () ->
|
||||
if false
|
||||
# offset time by 10 minutes to get the 'you need to wait message' in
|
||||
untilTime = @getTimeRemaining(@props.subscription.until.total + (10 * 60 * 1000))
|
||||
else
|
||||
untilTime = @props.subscription.until
|
||||
timeString = ''
|
||||
if untilTime.days != 0
|
||||
timeString += "#{untilTime.days} days, "
|
||||
if untilTime.hours != 0 || timeString.length > 0
|
||||
timeString += "#{untilTime.hours} hours, "
|
||||
if untilTime.minutes != 0 || timeString.length > 0
|
||||
timeString += "#{untilTime.minutes} minutes, "
|
||||
if untilTime.seconds != 0 || timeString.length > 0
|
||||
timeString += "#{untilTime.seconds} seconds"
|
||||
|
||||
if timeString == ''
|
||||
'now!'
|
||||
timeString
|
||||
|
||||
openBrowserToPayment: (e) ->
|
||||
context.JK.popExternalLink("/client#/account/subscription", true)
|
||||
e.stopPropagation();
|
||||
|
||||
openBrowserToPlanComparison: (e) ->
|
||||
context.JK.popExternalLink("https://jamkazam.freshdesk.com/support/solutions/articles/66000122535-what-are-jamkazam-s-free-vs-premium-features-")
|
||||
e.stopPropagation();
|
||||
return 'noclose'
|
||||
|
||||
|
||||
render: () ->
|
||||
content = null
|
||||
if @props.subscription.until.total < 2000
|
||||
content = `<div className="message">
|
||||
<p>You have run out of time.</p>
|
||||
<p>You can <a href="/client#/account/subscription" onClick={this.openBrowserToPayment}>upgrade your plan</a> to continue playing.</p>
|
||||
</div>`
|
||||
else
|
||||
if @props.subscription.main_concern_type == 'remaining_session_play_time'
|
||||
content = `<div className="message">
|
||||
<p>You will run out play time for this session in:</p>
|
||||
<p className="time">{this.displayTime()}</p>
|
||||
<p>You can <a href="/client#/account/subscription" onClick={this.openBrowserToPayment}>upgrade your plan</a> to continue playing.</p>
|
||||
</div>`
|
||||
else
|
||||
content = `<div className="message">
|
||||
<p>You will run out of monthly play time in:</p>
|
||||
<p className="time">{this.displayTime()}</p>
|
||||
<p>You can <a href="/client#/account/subscription" onClick={this.openBrowserToPayment}>upgrade your plan</a> to continue playing.</p>
|
||||
</div>`
|
||||
|
||||
if content?
|
||||
`<div className="broadcast-notification subscription">
|
||||
{content}
|
||||
</div>`
|
||||
else
|
||||
`<div></div>`
|
||||
|
||||
})
|
||||
|
|
@ -6,14 +6,13 @@ ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
|
|||
@TopMessageHolder = React.createClass(
|
||||
{
|
||||
displayName: 'Top Message Holder',
|
||||
|
||||
mixins: [Reflux.listenTo(ConfigStore, "onConfig")]
|
||||
minimum_time_until_sub_prompt: 1000 * 60 * 30 # 30 minutes
|
||||
mixins: [Reflux.listenTo(ConfigStore, "onConfig"), Reflux.connect(context.JK.Stores.Broadcast, 'notification')]
|
||||
|
||||
getInitialState: () ->
|
||||
{}
|
||||
|
||||
onConfig: (configs) ->
|
||||
|
||||
if configs.top_message
|
||||
@setState({top_message: configs.top_message})
|
||||
|
||||
|
|
@ -23,7 +22,12 @@ ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
|
|||
return false
|
||||
|
||||
render: () ->
|
||||
if @state.top_message
|
||||
# only show the subscription concern message if there is a concerpn and due time is less thant 30 minutes away
|
||||
if @state.notification && @state.notification.subscriptionConcern? && @state.notification.subscriptionConcern.until.total < @minimum_time_until_sub_prompt
|
||||
`<div id="broadcast-notification-holder" className="broadcast-notification-holder" >
|
||||
<SubscriptionConcern key="subscriptionconcern" subscription={this.state.notification.subscriptionConcern} />
|
||||
</div>`
|
||||
else if @state.top_message
|
||||
`<div id="broadcast-notification-holder" className="broadcast-notification-holder" >
|
||||
<div className="broadcast-notification config" dangerouslySetInnerHTML={{__html:this.state.top_message}}>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
context = window
|
||||
|
||||
@SubscriptionActions = Reflux.createActions({
|
||||
updateSubscription: {}
|
||||
changeSubscription: {}
|
||||
cancelSubscription: {}
|
||||
updatePayment: {}
|
||||
})
|
||||
|
|
@ -2,7 +2,7 @@ context = window
|
|||
|
||||
@SessionHelper = class SessionHelper
|
||||
|
||||
constructor: (app, session, participantsEverSeen, isRecording, downloadingJamTrack, preppingVstEnable) ->
|
||||
constructor: (app, session, participantsEverSeen, isRecording, downloadingJamTrack, preppingVstEnable, sessionRules, subscriptionRules) ->
|
||||
@app = app
|
||||
@session = session
|
||||
@participantsEverSeen = participantsEverSeen
|
||||
|
|
@ -10,6 +10,8 @@ context = window
|
|||
@downloadingJamTrack = downloadingJamTrack
|
||||
@preppingVstEnable = preppingVstEnable
|
||||
@isLesson = @session?.lesson_session?
|
||||
@sessionRules = sessionRules
|
||||
@subscriptionRules = subscriptionRules
|
||||
if @isLesson
|
||||
@lessonId = @session.lesson_session.id
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ $ = jQuery
|
|||
context = window
|
||||
logger = context.JK.logger
|
||||
broadcastActions = @BroadcastActions
|
||||
SessionActions = @SessionActions
|
||||
|
||||
rest = context.JK.Rest()
|
||||
|
||||
|
|
@ -17,6 +18,10 @@ BroadcastStore = Reflux.createStore(
|
|||
currentLessonTimer: null
|
||||
teacherFault: false
|
||||
isJamClass: false
|
||||
sessionRules: null
|
||||
subscriptionRules: null
|
||||
subscriptionConcern: null
|
||||
currentSubscriptionTimer: null
|
||||
init: ->
|
||||
this.listenTo(context.AppStore, this.onAppInit)
|
||||
this.listenTo(context.SessionStore, this.onSessionChange)
|
||||
|
|
@ -29,6 +34,45 @@ BroadcastStore = Reflux.createStore(
|
|||
@timeManagement()
|
||||
@changed()
|
||||
|
||||
subscriptionTick: () ->
|
||||
@subscriptionManagement()
|
||||
@changed()
|
||||
|
||||
openBrowserToPayment: () ->
|
||||
context.JK.popExternalLink("/client#/account/subscription", true)
|
||||
|
||||
openBrowserToPlanComparison: () ->
|
||||
context.JK.popExternalLink("https://jamkazam.freshdesk.com/support/solutions/articles/66000122535-what-are-jamkazam-s-free-vs-premium-features-")
|
||||
return 'noclose'
|
||||
|
||||
subscriptionManagement: () ->
|
||||
@subscriptionConcern.until = @lessonUtils.getTimeRemaining(@subscriptionConcern.main_concern_time)
|
||||
if @subscriptionConcern.until.total < -15000
|
||||
leaveBehavior =
|
||||
location: "/client#/findSession"
|
||||
buttons = []
|
||||
buttons.push({name: 'CLOSE', buttonStyle: 'button-grey'})
|
||||
buttons.push({name: 'COMPARE PLANS', buttonStyle: 'button-grey', click: (() => (@openBrowserToPlanComparison()))})
|
||||
buttons.push({
|
||||
name: 'UPGRADE PLAN',
|
||||
buttonStyle: 'button-orange',
|
||||
click: (() => (@openBrowserToPayment()))
|
||||
})
|
||||
|
||||
if @subscriptionConcern.main_concern_type == "remaining_month_play_time"
|
||||
context.JK.Banner.show({
|
||||
title: "Out of Time For This Month",
|
||||
html: context._.template($('#template-no-remaining-month-play-time').html(), {}, { variable: 'data' }),
|
||||
buttons: buttons});
|
||||
else
|
||||
context.JK.Banner.show({
|
||||
title: "Out of Time For This Session",
|
||||
html: context._.template($('#template-no-remaining-session-play-time').html(), {}, { variable: 'data' }),
|
||||
buttons: buttons});
|
||||
|
||||
SessionActions.leaveSession.trigger(leaveBehavior)
|
||||
|
||||
|
||||
timeManagement: () ->
|
||||
lastCheck = $.extend({}, @currentLesson)
|
||||
lessonSession = @currentLesson
|
||||
|
|
@ -61,7 +105,7 @@ BroadcastStore = Reflux.createStore(
|
|||
logger.debug("BroadcastStore: lesson is over")
|
||||
@currentLesson.completed = true
|
||||
@currentLesson.success = @analysis.success
|
||||
@clearTimer()
|
||||
@clearLessonTimer()
|
||||
@changed()
|
||||
else if @analysis.analysis.reason != 'teacher_fault'
|
||||
logger.debug("BroadcastStore: not teacher fault; clearing lesson info")
|
||||
|
|
@ -69,21 +113,31 @@ BroadcastStore = Reflux.createStore(
|
|||
else
|
||||
logger.debug("BroadcastStore: teacher is at fault")
|
||||
@teacherFault = true
|
||||
@clearTimer()
|
||||
@clearLessonTimer()
|
||||
@changed()
|
||||
|
||||
clearLesson: () ->
|
||||
if @currentLesson?
|
||||
@currentLesson = null
|
||||
@clearTimer()
|
||||
@clearLessonTimer()
|
||||
@teacherFault = false
|
||||
@changed()
|
||||
|
||||
clearTimer: () ->
|
||||
clearSubscription: () ->
|
||||
@subscriptionConcern = null
|
||||
@clearSubscriptionTimer()
|
||||
@changed()
|
||||
|
||||
clearLessonTimer: () ->
|
||||
if @currentLessonTimer?
|
||||
clearInterval(@currentLessonTimer)
|
||||
@currentLessonTimer = null
|
||||
|
||||
clearSubscriptionTimer: () ->
|
||||
if @currentSubscriptionTimer?
|
||||
clearInterval(@currentSubscriptionTimer)
|
||||
@currentSubscriptionTimer = null
|
||||
|
||||
onNavChange: (nav) ->
|
||||
path = nav.screenPath.toLowerCase()
|
||||
@isJamClass = path.indexOf('jamclass') > -1 || path.indexOf('teacher') > -1
|
||||
|
|
@ -93,29 +147,59 @@ BroadcastStore = Reflux.createStore(
|
|||
|
||||
@session = session
|
||||
currentSession = session.session
|
||||
if currentSession? && currentSession.lesson_session? && session.inSession()
|
||||
if currentSession? && session.inSession()
|
||||
@subscriptionRules = session.subscriptionRules
|
||||
@sessionRules = session.sessionRules
|
||||
|
||||
@currentSession = currentSession
|
||||
if @subscriptionRules
|
||||
|
||||
lessonSession = currentSession.lesson_session
|
||||
# so that receivers can check type of info coming at them via one-way events
|
||||
lessonSession.isLesson = true
|
||||
if !@subscriptionRules.remaining_month_until? && !@sessionRules.remaining_session_until?
|
||||
console.log("no license issues")
|
||||
@subscriptionConcern = null
|
||||
else
|
||||
@subscriptionConcern = {}
|
||||
if !@subscriptionRules.remaining_month_until?
|
||||
@subscriptionConcern.main_concern_time = @sessionRules.remaining_session_until
|
||||
@subscriptionConcern.main_concern_type = "remaining_session_play_time"
|
||||
else if !@sessionRules.remaining_session_play_time?
|
||||
@subscriptionConcern.main_concern_time = @subscriptionRules.remaining_month_until
|
||||
@subscriptionConcern.main_concern_type = "remaining_month_play_time"
|
||||
else
|
||||
if @sessionRules.remaining_session_play_time < @subscriptionRules.remaining_month_play_time
|
||||
@subscriptionConcern.main_concern_time = @sessionRules.remaining_session_until
|
||||
@subscriptionConcern.main_concern_type = "remaining_session_play_time"
|
||||
else
|
||||
@subscriptionConcern.main_concern_time = @subscriptionRules.remaining_month_until
|
||||
@subscriptionConcern.main_concern_type = "remaining_month_play_time"
|
||||
|
||||
if lessonSession.status == 'completed'
|
||||
lessonSession.completed = true
|
||||
lessonSession.success = lessonSession.success
|
||||
#else
|
||||
# rest.getLessonAnalysis({id: lessonSession.id}).done((response) => @lessonAnalysisDone(response)).fail(@app.ajaxError)
|
||||
@subscriptionManagement()
|
||||
#logger.debug("BroadcastStore: session can play until: ", @subscriptionConcern.until, @subscriptionConcern.main_concert_time)
|
||||
if !@currentSubscriptionTimer?
|
||||
@currentSubscriptionTimer= setInterval((() => @subscriptionTick()), 1000)
|
||||
@changed()
|
||||
|
||||
@currentLesson = lessonSession
|
||||
@timeManagement()
|
||||
logger.debug("BroadcastStore: currentLesson until: ", @currentLesson.until, lessonSession.scheduled_start)
|
||||
if !@currentLessonTimer?
|
||||
@currentLessonTimer = setInterval((() => @lessonTick()), 1000)
|
||||
@changed()
|
||||
if currentSession.lesson_session?
|
||||
@currentSession = currentSession
|
||||
|
||||
lessonSession = currentSession.lesson_session
|
||||
# so that receivers can check type of info coming at them via one-way events
|
||||
lessonSession.isLesson = true
|
||||
|
||||
if lessonSession.status == 'completed'
|
||||
lessonSession.completed = true
|
||||
lessonSession.success = lessonSession.success
|
||||
#else
|
||||
# rest.getLessonAnalysis({id: lessonSession.id}).done((response) => @lessonAnalysisDone(response)).fail(@app.ajaxError)
|
||||
|
||||
@currentLesson = lessonSession
|
||||
@timeManagement()
|
||||
logger.debug("BroadcastStore: currentLesson until: ", @currentLesson.until, lessonSession.scheduled_start)
|
||||
if !@currentLessonTimer?
|
||||
@currentLessonTimer = setInterval((() => @lessonTick()), 1000)
|
||||
@changed()
|
||||
else
|
||||
@clearLesson()
|
||||
@clearSubscription()
|
||||
|
||||
onLoad: () ->
|
||||
logger.debug("loading broadcast notification...")
|
||||
|
|
@ -136,21 +220,10 @@ BroadcastStore = Reflux.createStore(
|
|||
@changed()
|
||||
|
||||
changed: () ->
|
||||
if @currentLesson?
|
||||
@currentLesson.isStudent == @currentLesson.student_id == context.JK.currentUserId
|
||||
@currentLesson.isTeacher = !@currentLesson.isStudent
|
||||
@currentLesson.teacherFault = @teacherFault
|
||||
@currentLesson.teacherPresent = @session.findParticipantByUserId(@currentLesson.teacher_id)
|
||||
@currentLesson.studentPresent = @session.findParticipantByUserId(@currentLesson.student_id)
|
||||
if (@currentLesson.teacherPresent? && @currentLesson.isStudent) || (@currentLesson.studentPresent? && @currentLesson.isTeacher)
|
||||
# don't show anything if the other person is there
|
||||
this.trigger(null)
|
||||
else
|
||||
this.trigger(@currentLesson)
|
||||
else if @isJamClass
|
||||
this.trigger({isJamClass: true})
|
||||
if @subscriptionConcern?
|
||||
this.trigger({subscriptionConcern: @subscriptionConcern})
|
||||
else
|
||||
this.trigger(@broadcast)
|
||||
this.trigger(null)
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ ConfigureTracksActions = @ConfigureTracksActions
|
|||
currentSessionId: null
|
||||
currentSession: null
|
||||
currentOrLastSession: null
|
||||
sessionRules: null
|
||||
subscriptionRules: null
|
||||
startTime: null
|
||||
currentParticipants: {}
|
||||
participantsEverSeen: {}
|
||||
|
|
@ -53,7 +55,7 @@ ConfigureTracksActions = @ConfigureTracksActions
|
|||
@sessionUtils = context.JK.SessionUtils
|
||||
@recordingModel = new context.JK.RecordingModel(@app, rest, context.jamClient);
|
||||
RecordingActions.initModel(@recordingModel)
|
||||
@helper = new context.SessionHelper(@app, @currentSession, @participantsEverSeen, @isRecording, @downloadingJamTrack, @enableVstTimeout?)
|
||||
@helper = new context.SessionHelper(@app, @currentSession, @participantsEverSeen, @isRecording, @downloadingJamTrack, @enableVstTimeout?, @sessionRules, @subscriptionRules)
|
||||
|
||||
onSessionJoinedByOther: (payload) ->
|
||||
clientId = payload.client_id
|
||||
|
|
@ -78,7 +80,7 @@ ConfigureTracksActions = @ConfigureTracksActions
|
|||
onVideoChanged: (@videoState) ->
|
||||
|
||||
issueChange: () ->
|
||||
@helper = new context.SessionHelper(@app, @currentSession, @participantsEverSeen, @isRecording, @downloadingJamTrack, @enableVstTimeout?)
|
||||
@helper = new context.SessionHelper(@app, @currentSession, @participantsEverSeen, @isRecording, @downloadingJamTrack, @enableVstTimeout?, @sessionRules, @subscriptionRules)
|
||||
this.trigger(@helper)
|
||||
|
||||
onWindowBackgrounded: () ->
|
||||
|
|
@ -726,6 +728,13 @@ ConfigureTracksActions = @ConfigureTracksActions
|
|||
deferred.resolve();
|
||||
deferred
|
||||
|
||||
openBrowserToPayment: () ->
|
||||
context.JK.popExternalLink("/client#/account/subscription", true)
|
||||
|
||||
openBrowserToPlanComparison: () ->
|
||||
context.JK.popExternalLink("https://jamkazam.freshdesk.com/support/solutions/articles/66000122535-what-are-jamkazam-s-free-vs-premium-features-")
|
||||
return 'noclose'
|
||||
|
||||
joinSession: () ->
|
||||
context.jamClient.SessionRegisterCallback("JK.HandleBridgeCallback2");
|
||||
context.jamClient.RegisterRecordingCallbacks("JK.HandleRecordingStartResult", "JK.HandleRecordingStopResult", "JK.HandleRecordingStarted", "JK.HandleRecordingStopped", "JK.HandleRecordingAborted");
|
||||
|
|
@ -816,13 +825,44 @@ ConfigureTracksActions = @ConfigureTracksActions
|
|||
@app.notifyAlert("No Inputs Configured", $('<span>You will need to reconfigure your audio device.</span>'))
|
||||
|
||||
else if response["errors"] && response["errors"]["music_session"] && response["errors"]["music_session"][0] == ["is currently recording"]
|
||||
|
||||
leaveBehavior =
|
||||
location: "/client#/findSession"
|
||||
notify:
|
||||
title: "Unable to Join Session"
|
||||
text: "The session is currently recording."
|
||||
SessionActions.leaveSession.trigger(leaveBehavior)
|
||||
else if response["errors"] && response["errors"]["remaining_session_play_time"]
|
||||
leaveBehavior =
|
||||
location: "/client#/findSession"
|
||||
buttons = []
|
||||
buttons.push({name: 'CLOSE', buttonStyle: 'button-grey'})
|
||||
buttons.push({name: 'COMPARE PLANS', buttonStyle: 'button-grey', click: (() => (@openBrowserToPlanComparison()))})
|
||||
buttons.push({
|
||||
name: 'UPGRADE PLAN',
|
||||
buttonStyle: 'button-orange',
|
||||
click: (() => (@openBrowserToPayment()))
|
||||
})
|
||||
context.JK.Banner.show({
|
||||
title: "Out of Time For This Session",
|
||||
html: context._.template($('#template-no-remaining-session-play-time').html(), {}, { variable: 'data' }),
|
||||
buttons: buttons});
|
||||
SessionActions.leaveSession.trigger(leaveBehavior)
|
||||
else if response["errors"] && response["errors"]["remaining_month_play_time"]
|
||||
leaveBehavior =
|
||||
location: "/client#/findSession"
|
||||
buttons = []
|
||||
buttons.push({name: 'CLOSE', buttonStyle: 'button-grey'})
|
||||
buttons.push({name: 'COMPARE PLANS', buttonStyle: 'button-grey', click: (() => (@openBrowserToPlanComparison()))})
|
||||
buttons.push({
|
||||
name: 'UPGRADE PLAN',
|
||||
buttonStyle: 'button-orange',
|
||||
click: (() => (@openBrowserToPayment()))
|
||||
})
|
||||
context.JK.Banner.show({
|
||||
title: "Out of Time for the Month",
|
||||
html: context._.template($('#template-no-remaining-month-play-time').html(), {}, { variable: 'data' }),
|
||||
buttons: buttons});
|
||||
SessionActions.leaveSession.trigger(leaveBehavior)
|
||||
else
|
||||
@app.notifyServerError(xhr, 'Unable to Join Session');
|
||||
else
|
||||
|
|
@ -1051,6 +1091,30 @@ ConfigureTracksActions = @ConfigureTracksActions
|
|||
if sessionData != null
|
||||
@currentOrLastSession = sessionData
|
||||
|
||||
if sessionData.session_rules
|
||||
@sessionRules = sessionData.session_rules
|
||||
# TESTING:
|
||||
@sessionRules.remaining_session_play_time = 60 * 30 + 15 # 30 minutes and 15 seconds
|
||||
|
||||
# compute timestamp due time
|
||||
if @sessionRules.remaining_session_play_time?
|
||||
until_time = new Date()
|
||||
until_time = new Date(until_time.getTime() + @sessionRules.remaining_session_play_time * 1000)
|
||||
@sessionRules.remaining_session_until = until_time
|
||||
|
||||
|
||||
if sessionData.subscription_rules
|
||||
@subscriptionRules = sessionData.subscription_rules
|
||||
# TESTING:
|
||||
#@subscriptionRules.remaining_month_play_time = 60 * 30 + 15 # 30 minutes and 15 seconds
|
||||
|
||||
if @subscriptionRules.remaining_month_play_time?
|
||||
until_time = new Date()
|
||||
until_time = new Date(until_time.getTime() + @subscriptionRules.remaining_month_play_time * 1000)
|
||||
#until_time.setSeconds(until_time.getSeconds() + @subscriptionRules.remaining_month_play_time)
|
||||
@subscriptionRules.remaining_month_until = until_time
|
||||
|
||||
|
||||
@currentSession = sessionData
|
||||
|
||||
if context.jamClient.UpdateSessionInfo?
|
||||
|
|
@ -1078,6 +1142,7 @@ ConfigureTracksActions = @ConfigureTracksActions
|
|||
# called by anyone wanting to leave the session with a certain behavior
|
||||
onLeaveSession: (behavior) ->
|
||||
logger.debug("attempting to leave session", behavior)
|
||||
|
||||
if behavior.notify
|
||||
@app.layout.notify(behavior.notify)
|
||||
|
||||
|
|
@ -1206,6 +1271,8 @@ ConfigureTracksActions = @ConfigureTracksActions
|
|||
@joinDeferred = null
|
||||
@isRecording = false
|
||||
@currentSessionId = null
|
||||
@sessionRules = null
|
||||
@subscriptionRules = null
|
||||
@currentParticipants = {}
|
||||
@previousAllTracks = {userTracks: [], backingTracks: [], metronomeTracks: []}
|
||||
@openBackingTrack = null
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
$ = jQuery
|
||||
context = window
|
||||
logger = context.JK.logger
|
||||
|
||||
@SubscriptionStore = Reflux.createStore(
|
||||
{
|
||||
listenables: @SubscriptionActions
|
||||
|
||||
subscription: null
|
||||
|
||||
|
||||
init: ->
|
||||
this.listenTo(context.AppStore, this.onAppInit)
|
||||
|
||||
onAppInit: (@app) ->
|
||||
|
||||
onUpdateSubscription: (subscription) ->
|
||||
|
||||
rest.getSubscription().done (subscription) =>
|
||||
@subscription = subscription
|
||||
console.log("subscription store update", subscription)
|
||||
@trigger(@subscription)
|
||||
.fail(() =>
|
||||
@app.layout.notify({
|
||||
title: "unable to fetch subscription status",
|
||||
text: "Please contact support@jamkazam.com"
|
||||
})
|
||||
)
|
||||
|
||||
onChangeSubscription: (plan_code) ->
|
||||
rest.changeSubscription({plan_code: plan_code}).done((subscription) =>
|
||||
@subscription = subscription
|
||||
console.log("subscription change update", subscription)
|
||||
@app.layout.notify({
|
||||
title: "Subscription updated!",
|
||||
text: "Thank you for supporting JamKazam!"
|
||||
})
|
||||
@trigger(@subscription)
|
||||
)
|
||||
.fail((jqXHR) =>
|
||||
if jqXHR.status == 422
|
||||
@app.layout.notify({
|
||||
title: "you already have this subscription",
|
||||
text: "No changes were made to your account."
|
||||
})
|
||||
else
|
||||
@app.layout.notify({
|
||||
title: "unable to update subscription status",
|
||||
text: "Please contact support@jamkazam.com. Error:\n #{jqXHR.responseText}"
|
||||
})
|
||||
)
|
||||
|
||||
onCancelSubscription: () ->
|
||||
rest.cancelSubscription().done((result) =>
|
||||
@subscription = {}
|
||||
console.log("cancelled successfully")
|
||||
@trigger(@subscription)
|
||||
)
|
||||
.fail((jqXHR) =>
|
||||
@app.layout.notify({
|
||||
title: "Subscription Cancelled",
|
||||
text: "Thanks for being a supporter!"
|
||||
})
|
||||
)
|
||||
}
|
||||
)
|
||||
|
|
@ -1209,7 +1209,7 @@
|
|||
$links.on('click', popOpenBrowser);
|
||||
}
|
||||
|
||||
context.JK.popExternalLink = function (href) {
|
||||
context.JK.popExternalLink = function (href, login) {
|
||||
if (!context.jamClient) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1220,11 +1220,28 @@
|
|||
href = window.location.protocol + '//' + window.location.host + href;
|
||||
}
|
||||
|
||||
if(login) {
|
||||
var rememberToken = $.cookie("remember_token");
|
||||
if(rememberToken) {
|
||||
href = window.location.protocol + '//' + window.location.host + "/passthrough?redirect-to=" + encodeURIComponent(href) + '&stoken=' + encodeURIComponent(rememberToken)
|
||||
}
|
||||
|
||||
}
|
||||
context.jamClient.OpenSystemBrowser(href);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
context.JK.popExternalLinkAndLogin = function(href) {
|
||||
|
||||
var rememberToken = $.cookie("remember_token");
|
||||
|
||||
context.JK.popExternalLink("https://jamkazam.freshdesk.com/support/solutions/articles/66000122535-what-are-jamkazam-s-free-vs-premium-features-")
|
||||
if(rememberToken) {
|
||||
"https://"
|
||||
}
|
||||
}
|
||||
|
||||
context.JK.checkbox = function ($checkbox, dark) {
|
||||
if (dark){
|
||||
return $checkbox.iCheck({
|
||||
|
|
|
|||
|
|
@ -18,13 +18,29 @@
|
|||
padding-top: 20px;
|
||||
}
|
||||
|
||||
#subscription-account-data {
|
||||
#subscription-account-data, #subscription-elements {
|
||||
display:grid;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
#justify-content: center;
|
||||
grid-template-columns: 50% 50%;
|
||||
}
|
||||
|
||||
#subscription-form {
|
||||
|
||||
}
|
||||
|
||||
#change-subscription-form {
|
||||
max-width:35rem;
|
||||
display:grid;
|
||||
align-items: center;
|
||||
#justify-content: center;
|
||||
grid-template-columns: 8rem 8rem 8rem;
|
||||
}
|
||||
|
||||
.payment-block {
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
form {
|
||||
max-width:25rem;
|
||||
}
|
||||
|
|
@ -63,7 +79,7 @@
|
|||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
#border-radius: 0;
|
||||
color: black;
|
||||
-webkit-appearance: none;
|
||||
-webkit-transition: border-color 0.3s;
|
||||
|
|
@ -140,4 +156,9 @@
|
|||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight:bold;
|
||||
margin:30px 0 20px;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,19 @@
|
|||
width:100%;
|
||||
}
|
||||
}
|
||||
|
||||
&.subscription {
|
||||
border-width:0;
|
||||
p {
|
||||
text-align:center;
|
||||
color:$ColorTextTypical;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
.message {
|
||||
width:100%;
|
||||
font-size:18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.message {
|
||||
float:left;
|
||||
|
|
|
|||
|
|
@ -339,12 +339,29 @@ class ApiMusicSessionsController < ApiController
|
|||
params[:parent_client_id]
|
||||
)
|
||||
|
||||
|
||||
if @connection.errors.any?
|
||||
response.status = :unprocessable_entity
|
||||
respond_with @connection
|
||||
else
|
||||
|
||||
@music_session = @connection.music_session
|
||||
|
||||
# used in rabl to render extra data
|
||||
@on_join = true
|
||||
@subscription_rules = current_user.subscription_rules
|
||||
@session_rules = { remaining_session_play_time: @music_session.play_time_remaining(current_user) }
|
||||
|
||||
# check if the user has gone past acceptable play time
|
||||
if !@session_rules[:remaining_session_play_time].nil? && @session_rules[:remaining_session_play_time] <= 0
|
||||
# user has no session time for this session left.
|
||||
render :json => { :errors => {:remaining_session_play_time => ['none remaining']}}, :status => 422
|
||||
return
|
||||
elsif !@subscription_rules[:remaining_month_play_time].nil? && @subscription_rules[:remaining_month_play_time] <= 0
|
||||
# user has no session time this month.
|
||||
render :json => { :errors => {:remaining_month_play_time=> ['none remaining']}}, :status => 422
|
||||
return
|
||||
end
|
||||
|
||||
respond_with @music_session, responder: ApiResponder, :status => 201, :location => api_session_detail_url(@connection.music_session)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ class ApiRecurlyController < ApiController
|
|||
render json: {message: x.inspect, errors: x.errors}, :status => 404
|
||||
end
|
||||
|
||||
def create_subscriptions
|
||||
def create_subscription
|
||||
begin
|
||||
sale = Sale.purchase_subscription(current_user, params[:recurly_token], params[:plan_code])
|
||||
subscription = Recurly::Subscription.find(current_user.recurly_subscription_id)
|
||||
|
|
@ -135,11 +135,10 @@ class ApiRecurlyController < ApiController
|
|||
end
|
||||
|
||||
def get_subscription
|
||||
subscription_id = current_user.recurly_subscription_id
|
||||
subscription = Recurly::Subscription.find(subscription_id) if subscription_id
|
||||
subscription = @client.find_subscription(current_user)
|
||||
|
||||
if subscription
|
||||
render :json => subscription
|
||||
render :json => subscription.to_json
|
||||
else
|
||||
render :json => {}
|
||||
end
|
||||
|
|
@ -148,8 +147,13 @@ class ApiRecurlyController < ApiController
|
|||
def cancel_subscription
|
||||
begin
|
||||
@client.cancel_subscription(current_user.recurly_subscription_id)
|
||||
subscription = Recurly::Subscription.find(current_user.recurly_subscription_id)
|
||||
render :json => subscription.to_json
|
||||
subscription = @client.find_subscription(current_user)
|
||||
|
||||
if subscription
|
||||
render :json => subscription.to_json
|
||||
else
|
||||
render :json => {}
|
||||
end
|
||||
rescue RecurlyClientError => x
|
||||
render json: {:message => x.inspect, errors: x.errors}, :status => 404
|
||||
end
|
||||
|
|
@ -157,9 +161,14 @@ class ApiRecurlyController < ApiController
|
|||
|
||||
def change_subscription_plan
|
||||
begin
|
||||
@client.change_subscription_plan(current_user.recurly_subscription_id, params[:plan_code])
|
||||
subscription = Recurly::Subscription.find(current_user.recurly_subscription_id)
|
||||
render :json => subscription.to_json
|
||||
result = @client.change_subscription_plan(current_user, params[:plan_code])
|
||||
if !result
|
||||
render json: {:message => "No change made to plan"}, :status => 422
|
||||
else
|
||||
subscription = Recurly::Subscription.find(current_user.recurly_subscription_id)
|
||||
render :json => subscription.to_json
|
||||
end
|
||||
|
||||
rescue RecurlyClientError => x
|
||||
render json: {:message => x.inspect, errors: x.errors}, :status => 404
|
||||
end
|
||||
|
|
@ -167,7 +176,7 @@ class ApiRecurlyController < ApiController
|
|||
|
||||
def change_subscription_payment
|
||||
begin
|
||||
@client.change_subscription_payment(current_user.recurly_subscription_id, params[:recurly_token], params[:billing_ifo])
|
||||
@client.change_subscription_payment(current_user.recurly_subscription_id, params[:recurly_token], params[:billing_info])
|
||||
subscription = Recurly::Subscription.find(current_user.recurly_subscription_id)
|
||||
render :json => subscription.to_json
|
||||
rescue RecurlyClientError => x
|
||||
|
|
|
|||
|
|
@ -494,13 +494,13 @@ class ApiUsersController < ApiController
|
|||
limit = 20 if limit <= 0
|
||||
offset = params[:offset].to_i
|
||||
offset = 0 if offset < 0
|
||||
@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')
|
||||
@notifications = Notification.joins(:source_user).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
|
||||
limit = params[:limit].to_i
|
||||
limit = 20 if limit <= 0
|
||||
offset = params[:offset].to_i
|
||||
offset = 0 if offset < 0
|
||||
@notifications = @user.notifications.offset(offset).limit(limit)
|
||||
@notifications = @user.notifications.joins(:source_user).offset(offset).limit(limit)
|
||||
end
|
||||
|
||||
respond_with @notifications, responder: ApiResponder, :status => 200
|
||||
|
|
|
|||
|
|
@ -326,6 +326,17 @@ class SessionsController < ApplicationController
|
|||
render :json => {has_google_auth: (!!current_user && !!UserAuthorization.google_auth(current_user).first)}
|
||||
end
|
||||
|
||||
def passthrough
|
||||
if params['stoken']
|
||||
# should be a remember_me cookie. log them in and redirect
|
||||
user = User.find_by_remember_token(params['stoken'])
|
||||
if !user.nil?
|
||||
sign_in user
|
||||
end
|
||||
end
|
||||
redirect_after_signin('/')
|
||||
end
|
||||
|
||||
def redirect_after_signin(default)
|
||||
redirect_to(params['redirect-to'].blank? ? default : params['redirect-to'])
|
||||
end
|
||||
|
|
|
|||
|
|
@ -93,4 +93,6 @@ module MusicSessionHelper
|
|||
def timezone_list(options)
|
||||
select_tag('timezone-list', timezone_options, options)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,6 +15,16 @@ else
|
|||
|
||||
attributes :id, :name, :description, :musician_access, :approval_required, :friends_can_join, :fan_access, :fan_chat, :band_id, :user_id, :claimed_recording_initiator_id, :track_changes_counter, :max_score, :backing_track_path, :metronome_active, :jam_track_initiator_id, :jam_track_id, :music_session_id_int
|
||||
|
||||
if @on_join
|
||||
node :subscription_rules do |session|
|
||||
@subscription_rules
|
||||
end
|
||||
|
||||
node :session_rules do |session|
|
||||
@session_rules
|
||||
end
|
||||
end
|
||||
|
||||
node :can_join do |session|
|
||||
session.can_join?(current_user, true)
|
||||
end
|
||||
|
|
@ -53,7 +63,7 @@ else
|
|||
attributes :ip_address, :client_id, :joined_session_at, :audio_latency, :id, :metronome_open, :is_jamblaster, :client_role, :parent_client_id, :client_id_int
|
||||
|
||||
node :user do |connection|
|
||||
{ :id => connection.user.id, :photo_url => connection.user.photo_url, :name => connection.user.name, :is_friend => connection.user.friends?(current_user), :connection_state => connection.aasm_state }
|
||||
{ :id => connection.user.id, :photo_url => connection.user.photo_url, :name => connection.user.name, :is_friend => connection.user.friends?(current_user), :connection_state => connection.aasm_state, :subscription => connection.user.subscription_plan_code }
|
||||
end
|
||||
|
||||
child(:tracks => :tracks) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#account-subscription.screen.secondary layout="screen" layout-id="account/subscription"
|
||||
.content-head
|
||||
.content-head{style="height:26px"}
|
||||
.content-icon
|
||||
= image_tag "content/icon_account.png", :size => "27x20"
|
||||
h1
|
||||
|
|
|
|||
|
|
@ -276,6 +276,18 @@ script type="text/template" id="template-help-jamtrack-controls-disabled"
|
|||
script type="text/template" id="template-help-volume-media-mixers"
|
||||
| Audio files only expose both master and personal mix controls, so any change here will also affect everyone in the session.
|
||||
|
||||
script type="text/template" id="template-no-remaining-session-play-time"
|
||||
.no-remaining-session-play-time
|
||||
p There is no more time left in this session. You can upgrade your plan.
|
||||
|
||||
script type="text/template" id="template-no-remaining-month-play-time"
|
||||
.no-remaining-monthly-play-time
|
||||
p There is no more session time left for this month. You can upgrade your plan.
|
||||
|
||||
script type="text/template" id="template-session-too-big-kicked"
|
||||
.session-too-big-kicked
|
||||
p Due to your current plan, you were forced to leave the session because someone else joined the session just now. You can upgrade your plan.
|
||||
|
||||
script type="text/template" id="template-help-downloaded-jamtrack"
|
||||
.downloaded-jamtrack
|
||||
p When a JamTrack is first purchased, a user-specific version of it is created on the server. Once it's ready, it's then downloaded to the client.
|
||||
|
|
|
|||
|
|
@ -482,6 +482,6 @@ if defined?(Bundler)
|
|||
config.root_redirect_on = true
|
||||
config.root_redirect_subdomain = ''
|
||||
config.root_redirect_path = '/'
|
||||
|
||||
config.subscription_codes = [{id: 'jamsubsilver', name: 'Silver', price: 4.99}, {id: 'jamsubgold', name: 'Gold', price:9.99}, {id: 'jamsubplatinum', name: 'Platinum', price:19.99}]
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,4 +26,5 @@ Gon.global.vst_enabled = Rails.application.config.vst_enabled
|
|||
Gon.global.chat_opened_by_default = Rails.application.config.chat_opened_by_default
|
||||
Gon.global.network_test_required = Rails.application.config.network_test_required
|
||||
Gon.global.musician_count = Rails.application.config.musician_count
|
||||
Gon.global.subscription_codes = Rails.application.config.subscription_codes
|
||||
Gon.global.env = Rails.env
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ Rails.application.routes.draw do
|
|||
get '/signin', to: 'sessions#signin'
|
||||
post '/signin', to: 'sessions#create'
|
||||
delete '/signout', to: 'sessions#destroy'
|
||||
get '/passthrough', to: 'sessions#passthrough'
|
||||
|
||||
match '/redeem_giftcard', to: 'landings#redeem_giftcard', via: :get
|
||||
match '/account/activate/code_old', to: 'landings#account_activate', via: :get
|
||||
|
|
@ -399,6 +400,11 @@ Rails.application.routes.draw do
|
|||
match '/recurly/update_billing_info' => 'api_recurly#update_billing_info', :via => :put
|
||||
match '/recurly/place_order' => 'api_recurly#place_order', :via => :post
|
||||
match '/ios/order_placed' => 'api_jam_tracks#ios_order_placed', :via => :post
|
||||
match '/recurly/create_subscription' => 'api_recurly#create_subscription', :via => :post
|
||||
match '/recurly/get_subscription' => 'api_recurly#get_subscription', :via => :get
|
||||
match '/recurly/change_subscription' => 'api_recurly#change_subscription_plan', :via => :post
|
||||
match '/recurly/cancel_subscription' => 'api_recurly#cancel_subscription', :via => :post
|
||||
match '/recurly/change_subscription_payment' => 'api_recurly#change_subscription_payment', :via => :post
|
||||
|
||||
# paypal
|
||||
match '/paypal/checkout/detail' => 'api_pay_pal#checkout_detail', :via => :post
|
||||
|
|
|
|||
|
|
@ -445,7 +445,7 @@ module JamWebsockets
|
|||
# a unique ID for this TCP connection, to aid in debugging
|
||||
client.channel_id = handshake.query["channel_id"]
|
||||
|
||||
@log.debug "client connected #{client} with channel_id: #{client.channel_id}"
|
||||
@log.debug "client connected #{client} with channel_id: #{client.channel_id} Original-IP: #{handshake.headers["X-Forwarded-For"]}"
|
||||
|
||||
|
||||
# check for '?pb' or '?pb=true' in url query parameters
|
||||
|
|
|
|||
Loading…
Reference in New Issue