merging
This commit is contained in:
commit
da58ac6eab
|
|
@ -32,6 +32,7 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
|
|||
row :birth_date
|
||||
row :gender
|
||||
row :email_confirmed
|
||||
row :remember_token
|
||||
row :image do user.photo_url ? image_tag(user.photo_url) : '' end
|
||||
end
|
||||
active_admin_comments
|
||||
|
|
|
|||
|
|
@ -290,3 +290,4 @@ jam_track_right_private_key.sql
|
|||
first_downloaded_jamtrack_at.sql
|
||||
signing.sql
|
||||
enhance_band_profile.sql
|
||||
optimized_redeemption.sql
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
CREATE TABLE machine_fingerprints (
|
||||
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
user_id VARCHAR(64) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
fingerprint VARCHAR(20000) NOT NULL UNIQUE,
|
||||
when_taken VARCHAR NOT NULL,
|
||||
print_type VARCHAR NOT NULL,
|
||||
remote_ip VARCHAR(1000) NOT NULL,
|
||||
jam_track_right_id BIGINT REFERENCES jam_track_rights(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
ALTER TABLE jam_track_rights ADD COLUMN redeemed_and_fingerprinted BOOLEAN DEFAULT FALSE;
|
||||
|
|
@ -103,6 +103,7 @@ require "jam_ruby/models/genre"
|
|||
require "jam_ruby/models/user"
|
||||
require "jam_ruby/models/anonymous_user"
|
||||
require "jam_ruby/models/signup_hint"
|
||||
require "jam_ruby/models/machine_fingerprint"
|
||||
require "jam_ruby/models/rsvp_request"
|
||||
require "jam_ruby/models/rsvp_slot"
|
||||
require "jam_ruby/models/rsvp_request_rsvp_slot"
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ module JamRuby
|
|||
|
||||
def generate_signup_url(invited_user)
|
||||
invited_user.generate_signup_url
|
||||
# "http://www.jamkazam.com/signup?invitation_code=#{invited_user.invitation_code}"
|
||||
# "https://www.jamkazam.com/signup?invitation_code=#{invited_user.invitation_code}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<br/>
|
||||
<br/>
|
||||
<p>
|
||||
This email was received because someone left feedback at <a style="color: #ffcc00;" href="http://www.jamkazam.com/corp/contact">http://www.jamkazam.com/corp/contact</a>
|
||||
This email was received because someone left feedback at <a style="color: #ffcc00;" href="https://www.jamkazam.com/corp/contact">http://www.jamkazam.com/corp/contact</a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ From <%= @email %>:
|
|||
<%= @body %>
|
||||
|
||||
|
||||
This email was received because someone left feedback at http://www.jamkazam.com/corp/contact
|
||||
This email was received because someone left feedback at https://www.jamkazam.com/corp/contact
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
</p>
|
||||
|
||||
<p>
|
||||
<a style="color: #ffcc00;" href="http://www.jamkazam.com/downloads">Go to Download Page</a>
|
||||
<a style="color: #ffcc00;" href="https://www.jamkazam.com/downloads">Go to Download Page</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
|||
|
||||
We noticed that you have registered as a JamKazam musician, but you have not yet downloaded and started using the free JamKazam application. You can find other musicians and listen to sessions and recordings on our website, but you need the free JamKazam application to play with other musicians online. Please click the link below to go to the download page for the free JamKazam application, or visit our JamKazam support center so that we can help you get up and running.
|
||||
|
||||
Go to Download Page: http://www.jamkazam.com/downloads
|
||||
Go to Download Page: https://www.jamkazam.com/downloads
|
||||
|
||||
Go to Support Center: https://jamkazam.desk.com
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
It’s still very early in our company’s development, so we don’t have zillions of users online on our service yet. If you click Find Session, you will often not find a good session to join, both due to the number of musicians online at any given time, and also because you won’t see private sessions where groups of musicians don’t want to be interrupted in their sessions.
|
||||
</p>
|
||||
|
||||
<p>If you are having trouble getting into sessions, we’d suggest you click the Musicians tile on the home screen of the app or the website: <a style="color: #ffcc00;" href="http://www.jamkazam.com/client#/musicians">Go To Musicians Page</a>
|
||||
<p>If you are having trouble getting into sessions, we’d suggest you click the Musicians tile on the home screen of the app or the website: <a style="color: #ffcc00;" href="https://www.jamkazam.com/client#/musicians">Go To Musicians Page</a>
|
||||
</p>
|
||||
|
||||
<p>This will display the JamKazam musicians sorted by latency to you - in other words, you can see which musicians have good network connections to you. Any musicians with green and yellow latency scores have good enough connections to support a play session with you. We recommend that read the profiles of these musicians to find others with shared musical interests and good network connections to you, and then use the Message button to say hi and see if they are interested in playing with you. If they are, use the Connect button to “friend” them on JamKazam, and use the Message button to set up a time to meet online for a session.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ We noticed that you haven’t yet played in a JamKazam session with multiple mus
|
|||
Find Other Musicians on JamKazam
|
||||
It’s still very early in our company’s development, so we don’t have zillions of users online on our service yet. If you click Find Session, you will often not find a good session to join, both due to the number of musicians online at any given time, and also because you won’t see private sessions where groups of musicians don’t want to be interrupted in their sessions.
|
||||
|
||||
If you are having trouble getting into sessions, we’d suggest you click the Musicians tile on the home screen of the app or the website: http://www.jamkazam.com/client#/musicians
|
||||
If you are having trouble getting into sessions, we’d suggest you click the Musicians tile on the home screen of the app or the website: https://www.jamkazam.com/client#/musicians
|
||||
|
||||
This will display the JamKazam musicians sorted by latency to you - in other words, you can see which musicians have good network connections to you. Any musicians with green and yellow latency scores have good enough connections to support a play session with you. We recommend that read the profiles of these musicians to find others with shared musical interests and good network connections to you, and then use the Message button to say hi and see if they are interested in playing with you. If they are, use the Connect button to “friend” them on JamKazam, and use the Message button to set up a time to meet online for a session.
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
</p>
|
||||
|
||||
<p>Find Other Musicians on JamKazam<br />
|
||||
To find and connect with other musicians who are already on JamKazam, we’d suggest you click the Musicians tile on the home screen of the app or the website: <a style="color: #ffcc00;" href="http://www.jamkazam.com/client#/musicians">Go To Musicians Page</a>
|
||||
To find and connect with other musicians who are already on JamKazam, we’d suggest you click the Musicians tile on the home screen of the app or the website: <a style="color: #ffcc00;" href="https://www.jamkazam.com/client#/musicians">Go To Musicians Page</a>
|
||||
</p>
|
||||
|
||||
<p>This will display the JamKazam musicians sorted by latency to you - in other words, you can see which musicians have good network connections to you. Any musicians with green and yellow latency scores have good enough connections to support a play session with you. We recommend that you read the profiles of these musicians to find others with shared musical interests and good network connections to you, and then use the Message button to say hi and see if they are interested in playing with you. If they are, use the Connect button to “friend” them on JamKazam, and use the Message button to set up a time to meet online for a session.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
|||
We noticed that you haven’t yet connected with any friends on JamKazam. Connecting with friends is the best way to help you get into sessions with other musicians on JamKazam. Here are a couple of good ways to connect with others.
|
||||
|
||||
Find Other Musicians on JamKazam
|
||||
To find and connect with other musicians who are already on JamKazam, we’d suggest you click the Musicians tile on the home screen of the app or the website: http://www.jamkazam.com/client#/musicians
|
||||
To find and connect with other musicians who are already on JamKazam, we’d suggest you click the Musicians tile on the home screen of the app or the website: https://www.jamkazam.com/client#/musicians
|
||||
|
||||
This will display the JamKazam musicians sorted by latency to you - in other words, you can see which musicians have good network connections to you. Any musicians with green and yellow latency scores have good enough connections to support a play session with you. We recommend that you read the profiles of these musicians to find others with shared musical interests and good network connections to you, and then use the Message button to say hi and see if they are interested in playing with you. If they are, use the Connect button to “friend” them on JamKazam, and use the Message button to set up a time to meet online for a session.
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
</p>
|
||||
|
||||
<% [:twitter, :facebook, :google].each do |site| %>
|
||||
<%= link_to(image_tag("http://www.jamkazam.com/assets/content/icon_#{site}.png", :style => "vertical-align:top"), "http://www.jamkazam.com/endorse/@USERID/#{site}?src=email") %>
|
||||
<%= link_to(image_tag("https://www.jamkazam.com/assets/content/icon_#{site}.png", :style => "vertical-align:top"), "https://www.jamkazam.com/endorse/@USERID/#{site}?src=email") %>
|
||||
<% end %>
|
||||
|
||||
<p>-- Team JamKazam
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ Hello <%= EmailBatchProgression::VAR_FIRST_NAME %> --
|
|||
JamKazam is a young company/service built through the sweat and commitment of a small group of music-loving techies. Please help us continue to grow the service and attract more musicians to play online by liking and/or following us on Facebook, Twitter, and Google+. Just click the icons below to give us little push, thanks!
|
||||
|
||||
<% [:twitter, :facebook, :google].each do |site| %>
|
||||
http://www.jamkazam.com/endorse/@USERID/#{site}?src=email
|
||||
https://www.jamkazam.com/endorse/@USERID/#{site}?src=email
|
||||
|
||||
<% end %>
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ Hi <%= @user.first_name %>,
|
|||
<% end %>
|
||||
</table>
|
||||
</p>
|
||||
<p>There are currently <%= @new_musicians.size%> musicians on JamKazam with low enough latency Internet connections to you to support a good online session. To see ALL the JamKazam musicians with whom you may want to connect and play, view our Musicians page at: <a style="color: #ffcc00;" href="http://www.jamkazam.com/client#/musicians">http://www.jamkazam.com/client#/musicians</a>.
|
||||
<p>There are currently <%= @new_musicians.size%> musicians on JamKazam with low enough latency Internet connections to you to support a good online session. To see ALL the JamKazam musicians with whom you may want to connect and play, view our Musicians page at: <a style="color: #ffcc00;" href="https://www.jamkazam.com/client#/musicians">http://www.jamkazam.com/client#/musicians</a>.
|
||||
</p>
|
||||
|
||||
<p>Best Regards,</p>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ The following new musicians have joined JamKazam within the last week, and have
|
|||
<%= user.biography %>
|
||||
<% end %>
|
||||
|
||||
There are currently <%= @new_musicians.size%> musicians on JamKazam with low enough latency Internet connections to you to support a good online session. To see ALL the JamKazam musicians with whom you may want to connect and play, view our Musicians page at: http://www.jamkazam.com/client#/musicians.
|
||||
There are currently <%= @new_musicians.size%> musicians on JamKazam with low enough latency Internet connections to you to support a good online session. To see ALL the JamKazam musicians with whom you may want to connect and play, view our Musicians page at: https://www.jamkazam.com/client#/musicians.
|
||||
|
||||
Best Regards,
|
||||
Team JamKazam
|
||||
|
|
|
|||
|
|
@ -68,16 +68,16 @@
|
|||
<td><%= sess.genre.description %></td>
|
||||
<td>
|
||||
<%= sess.name %><br/>
|
||||
<a style="color: #ffcc00;" href="<%= "http://www.jamkazam.com/sessions/#{sess.id}/details" %>">Details</a>
|
||||
<a style="color: #ffcc00;" href="<%= "https://www.jamkazam.com/sessions/#{sess.id}/details" %>">Details</a>
|
||||
</td>
|
||||
<td><%= sess.description %></td>
|
||||
<td style="text-align:center">
|
||||
<span class="latency">
|
||||
<span class="latency-value"><%= (sess.latency / 2).round %> ms</span>
|
||||
<% if sess.latency <= (APP_CONFIG.max_good_full_score / 2) %>
|
||||
<%= image_tag("http://www.jamkazam.com/assets/content/icon_green_score.png", alt: 'good score icon') %>
|
||||
<%= image_tag("https://www.jamkazam.com/assets/content/icon_green_score.png", alt: 'good score icon') %>
|
||||
<% else %>
|
||||
<%= image_tag("http://www.jamkazam.com/assets/content/icon_yellow_score.png", alt: 'fair score icon') %>
|
||||
<%= image_tag("https://www.jamkazam.com/assets/content/icon_yellow_score.png", alt: 'fair score icon') %>
|
||||
<% end %>
|
||||
</span>
|
||||
</td>
|
||||
|
|
@ -86,7 +86,7 @@
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
<p>To see ALL the scheduled sessions that you might be interested in joining, view our <a style="color: #ffcc00;" href="http://www.jamkazam.com/client#/findSession">Find Session page</a>.</p>
|
||||
<p>To see ALL the scheduled sessions that you might be interested in joining, view our <a style="color: #ffcc00;" href="https://www.jamkazam.com/client#/findSession">Find Session page</a>.</p>
|
||||
|
||||
<p>Best Regards,</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ GENRE | NAME | DESCRIPTION | LATENCY
|
|||
<%= sess.genre.description %> | <%= sess.name %> | <%= sess.description %> | <%= sess.latency %> ms
|
||||
<% end %>
|
||||
|
||||
To see ALL the scheduled sessions that you might be interested in joining, view our Find Session page at: http://www.jamkazam.com/client#/findSession.
|
||||
To see ALL the scheduled sessions that you might be interested in joining, view our Find Session page at: https://www.jamkazam.com/client#/findSession.
|
||||
|
||||
Best Regards,
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
<body bgcolor="#000000" style="margin-top:10px;font-family:Arial, Helvetica, sans-serif;">
|
||||
<table bgcolor="#262626" width="650" align="center" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td><img src="http://www.jamkazam.com/assets/email/header.png" width="650" height="183" alt="JamKazam"></td>
|
||||
<td><img src="https://www.jamkazam.com/assets/email/header.png" width="650" height="183" alt="JamKazam"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table bgcolor="#262626" width="650" align="center" cellpadding="30" cellspacing="0">
|
||||
|
|
@ -51,7 +51,7 @@
|
|||
|
||||
<!-- CALL OUT BOX -->
|
||||
</font></p>
|
||||
<p style="margin-top:0px"><font size="2" color="#7FACBA" face="Arial, Helvetica, sans-serif">This email was sent to you because you have an account at <a style="color: #ffcc00;" href="http://www.jamkazam.com">JamKazam</a>.
|
||||
<p style="margin-top:0px"><font size="2" color="#7FACBA" face="Arial, Helvetica, sans-serif">This email was sent to you because you have an account at <a style="color: #ffcc00;" href="https://www.jamkazam.com">JamKazam</a>.
|
||||
</td></tr></table>
|
||||
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
|
||||
<% unless @suppress_user_has_account_footer == true %>
|
||||
This email was sent to you because you have an account at JamKazam / http://www.jamkazam.com.
|
||||
This email was sent to you because you have an account at JamKazam / https://www.jamkazam.com.
|
||||
<% end %>
|
||||
|
||||
Copyright <%= Time.now.year %> JamKazam, Inc. All rights reserved.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<% end %>
|
||||
|
||||
<% unless @user.nil? || @suppress_user_has_account_footer == true %>
|
||||
This email was sent to you because you have an account at JamKazam / http://www.jamkazam.com. To unsubscribe: http://www.jamkazam.com/unsubscribe/<%=@user.unsubscribe_token%>.
|
||||
This email was sent to you because you have an account at JamKazam / https://www.jamkazam.com. To unsubscribe: https://www.jamkazam.com/unsubscribe/<%=@user.unsubscribe_token%>.
|
||||
<% end %>
|
||||
|
||||
Copyright <%= Time.now.year %> JamKazam, Inc. All rights reserved.
|
||||
|
|
|
|||
|
|
@ -774,6 +774,7 @@ module JamRuby
|
|||
self.opening_jam_track = true
|
||||
self.save
|
||||
self.opening_jam_track = false
|
||||
#self.tick_track_changes
|
||||
end
|
||||
|
||||
def close_jam_track
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@
|
|||
module JamRuby
|
||||
class AnonymousUser
|
||||
|
||||
attr_accessor :id
|
||||
attr_accessor :id, :cookies
|
||||
|
||||
def initialize(id)
|
||||
def initialize(id, cookies)
|
||||
@id = id
|
||||
@cookies = cookies
|
||||
end
|
||||
|
||||
def shopping_carts
|
||||
|
|
@ -23,7 +24,11 @@ module JamRuby
|
|||
end
|
||||
|
||||
def has_redeemable_jamtrack
|
||||
APP_CONFIG.one_free_jamtrack_per_user
|
||||
APP_CONFIG.one_free_jamtrack_per_user && !@cookies[:redeemed_jamtrack]
|
||||
end
|
||||
|
||||
def signup_hint
|
||||
SignupHint.find_by_anonymous_user_id(@id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ module JamRuby
|
|||
:band_type, :band_status, :concert_count, :add_new_members, :play_commitment, :touring_option, :paid_gigs,
|
||||
:free_gigs, :hourly_rate, :gig_minimum
|
||||
|
||||
attr_accessor :updating_photo, :skip_location_validation
|
||||
attr_accessor :updating_photo, :skip_location_validation, :skip_genre_validation
|
||||
|
||||
self.primary_key = 'id'
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ module JamRuby
|
|||
validates :city, presence: true, :unless => :skip_location_validation
|
||||
|
||||
validate :validate_photo_info
|
||||
validate :require_at_least_one_genre
|
||||
validate :require_at_least_one_genre, :unless => :skip_genre_validation
|
||||
validate :limit_max_genres
|
||||
|
||||
before_save :check_lat_lng
|
||||
|
|
@ -199,7 +199,8 @@ module JamRuby
|
|||
band.genres = genres
|
||||
end
|
||||
|
||||
|
||||
band.skip_genre_validation = true unless params[:validate_genres]
|
||||
puts "SKIPPING GENRE VALIDATION: #{band.skip_genre_validation}"
|
||||
band
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ module JamRuby
|
|||
mount.source_pass = APP_CONFIG.icecast_hardcoded_source_password || SecureRandom.urlsafe_base64
|
||||
mount.stream_name = "JamKazam music session created by #{music_session.creator.name}"
|
||||
mount.stream_description = music_session.description
|
||||
mount.stream_url = "http://www.jamkazam.com" ## TODO/XXX, the jamkazam url should be the page hosting the widget
|
||||
mount.stream_url = "https://www.jamkazam.com" ## TODO/XXX, the jamkazam url should be the page hosting the widget
|
||||
mount.genre = music_session.genre.description
|
||||
mount
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,21 +3,24 @@ module JamRuby
|
|||
# describes what users have rights to which tracks
|
||||
class JamTrackRight < ActiveRecord::Base
|
||||
include JamRuby::S3ManagerMixin
|
||||
attr_accessible :user, :jam_track, :user_id, :jam_track_id, :download_count
|
||||
|
||||
@@log = Logging.logger[JamTrackRight]
|
||||
|
||||
attr_accessible :user, :jam_track, :user_id, :jam_track_id, :download_count
|
||||
attr_accessible :user_id, :jam_track_id, as: :admin
|
||||
attr_accessible :url_48, :md5_48, :length_48, :url_44, :md5_44, :length_44
|
||||
belongs_to :user, class_name: "JamRuby::User" # the owner, or purchaser of the jam_track
|
||||
belongs_to :user, class_name: "JamRuby::User" # the owner, or purchaser of the jam_track
|
||||
belongs_to :jam_track, class_name: "JamRuby::JamTrack"
|
||||
|
||||
validates :user, presence:true
|
||||
validates :jam_track, presence:true
|
||||
validates :is_test_purchase, inclusion: {in: [true, false]}
|
||||
validates :user, presence: true
|
||||
validates :jam_track, presence: true
|
||||
validates :is_test_purchase, inclusion: {in: [true, false]}
|
||||
|
||||
validate :verify_download_count
|
||||
after_save :after_save
|
||||
|
||||
validates_uniqueness_of :user_id, scope: :jam_track_id
|
||||
|
||||
validates_uniqueness_of :user_id, scope: :jam_track_id
|
||||
|
||||
# Uploads the JKZ:
|
||||
mount_uploader :url_48, JamTrackRightUploader
|
||||
mount_uploader :url_44, JamTrackRightUploader
|
||||
|
|
@ -42,7 +45,7 @@ module JamRuby
|
|||
def filename(bitrate)
|
||||
"#{jam_track.name}-#{bitrate == :url_48 ? '48' : '44'}.jkz"
|
||||
end
|
||||
|
||||
|
||||
def verify_download_count
|
||||
if (self.download_count < 0 || self.download_count > MAX_JAM_TRACK_DOWNLOADS) && !@current_user.admin
|
||||
errors.add(:download_count, "must be less than or equal to #{MAX_JAM_TRACK_DOWNLOADS}")
|
||||
|
|
@ -102,8 +105,8 @@ module JamRuby
|
|||
end
|
||||
|
||||
def delete_s3_files
|
||||
remove_url_48!
|
||||
remove_url_44!
|
||||
remove_url_48!
|
||||
remove_url_44!
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -211,6 +214,86 @@ module JamRuby
|
|||
.where('jam_tracks.id IN (?)', jamtracks)
|
||||
end
|
||||
|
||||
def guard_against_fraud(current_user, fingerprint, remote_ip)
|
||||
|
||||
if current_user.blank?
|
||||
return "no user specified"
|
||||
end
|
||||
|
||||
# admin's get to skip fraud check
|
||||
if current_user.admin
|
||||
return nil
|
||||
end
|
||||
|
||||
if fingerprint.nil? || fingerprint.empty?
|
||||
return "no fingerprint specified"
|
||||
end
|
||||
|
||||
all_fingerprint = fingerprint[:all]
|
||||
running_fingerprint = fingerprint[:running]
|
||||
|
||||
if all_fingerprint.blank?
|
||||
return "no all fingerprint specified"
|
||||
end
|
||||
|
||||
if running_fingerprint.blank?
|
||||
return "no running fingerprint specified"
|
||||
end
|
||||
|
||||
if redeemed && !redeemed_and_fingerprinted
|
||||
# if this is a free JamTrack, we need to check for fraud or accidental misuse
|
||||
|
||||
# first of all, does this user have any other JamTracks aside from this one that have already been redeemed it and are marked free?
|
||||
other_redeemed_freebie = JamTrackRight.where(redeemed: true).where(redeemed_and_fingerprinted: true).where('id != ?', id).where(user_id: current_user.id).first
|
||||
|
||||
if other_redeemed_freebie
|
||||
return "already redeemed another"
|
||||
end
|
||||
|
||||
# can we find a jam track that belongs to someone else with the same fingerprint
|
||||
match = MachineFingerprint.find_by_fingerprint(all_fingerprint)
|
||||
|
||||
if match && match.user != current_user
|
||||
AdminMailer.alerts(subject: "'All' fingerprint collision by #{current_user.name}",
|
||||
body: "MachineFingerprint #{match.inspect}\n\nCurrent User: #{current_user.admin_url}").deliver
|
||||
|
||||
# try to record the other fingerprint
|
||||
MachineFingerprint.create(running_fingerprint, current_user, MachineFingerprint::TAKEN_ON_FRAUD_CONFLICT, MachineFingerprint::PRINT_TYPE_ACTIVE, remote_ip, self)
|
||||
if APP_CONFIG.error_on_fraud
|
||||
return "other user has 'all' fingerprint"
|
||||
end
|
||||
end
|
||||
|
||||
if all_fingerprint != running_fingerprint
|
||||
match = MachineFingerprint.find_by_fingerprint(running_fingerprint)
|
||||
|
||||
if match && match.user != current_user
|
||||
AdminMailer.alerts(subject: "'Running' fingerprint collision by #{current_user.name}",
|
||||
body: "MachineFingerprint #{match.inspect}\n\nCurrent User: #{current_user.admin_url}").deliver
|
||||
# try to record the other fingerprint
|
||||
MachineFingerprint.create(all_fingerprint, current_user, MachineFingerprint::TAKEN_ON_FRAUD_CONFLICT, MachineFingerprint::PRINT_TYPE_ALL, remote_ip, self)
|
||||
if APP_CONFIG.error_on_fraud
|
||||
return "other user has 'running' fingerprint"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# we made it past all checks; let's slap on the redeemed_fingerprint
|
||||
self.redeemed_and_fingerprinted = true
|
||||
|
||||
|
||||
MachineFingerprint.create(all_fingerprint, current_user, MachineFingerprint::TAKEN_ON_SUCCESSFUL_DOWNLOAD, MachineFingerprint::PRINT_TYPE_ALL, remote_ip, self)
|
||||
if all_fingerprint != running_fingerprint
|
||||
MachineFingerprint.create(running_fingerprint, current_user, MachineFingerprint::TAKEN_ON_SUCCESSFUL_DOWNLOAD, MachineFingerprint::PRINT_TYPE_ACTIVE, remote_ip, self)
|
||||
end
|
||||
|
||||
save!
|
||||
end
|
||||
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
def self.stats
|
||||
stats = {}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
module JamRuby
|
||||
class MachineFingerprint < ActiveRecord::Base
|
||||
|
||||
@@log = Logging.logger[MachineFingerprint]
|
||||
|
||||
belongs_to :user, :class_name => "JamRuby::User"
|
||||
belongs_to :jam_track_right, :class_name => "JamRuby::JamTrackRight"
|
||||
|
||||
TAKEN_ON_SUCCESSFUL_DOWNLOAD = 'dl'
|
||||
TAKEN_ON_FRAUD_CONFLICT = 'fc'
|
||||
|
||||
PRINT_TYPE_ALL = 'a'
|
||||
PRINT_TYPE_ACTIVE = 'r'
|
||||
|
||||
|
||||
validates :user, presence:true
|
||||
validates :when_taken, :inclusion => {:in => [TAKEN_ON_SUCCESSFUL_DOWNLOAD, TAKEN_ON_FRAUD_CONFLICT]}
|
||||
validates :fingerprint, presence: true, uniqueness:true
|
||||
validates :print_type, presence: true, :inclusion => {:in =>[PRINT_TYPE_ALL, PRINT_TYPE_ACTIVE]}
|
||||
validates :remote_ip, presence: true
|
||||
|
||||
def self.create(fingerprint, user, when_taken, print_type, remote_ip, jam_track_right = nil)
|
||||
mf = MachineFingerprint.new
|
||||
mf.fingerprint = fingerprint
|
||||
mf.user = user
|
||||
mf.when_taken = when_taken
|
||||
mf.print_type = print_type
|
||||
mf.remote_ip = remote_ip
|
||||
mf.jam_track_right = jam_track_right
|
||||
unless mf.save
|
||||
@@log.error("unable to create machine fingerprint: #{mf.errors.inspect}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -128,6 +128,10 @@ module JamRuby
|
|||
# just a pain to implement
|
||||
end
|
||||
|
||||
def self.is_only_freebie(shopping_carts_jam_tracks)
|
||||
shopping_carts_jam_tracks.length == 1 && shopping_carts_jam_tracks[0].product_info[:free]
|
||||
end
|
||||
|
||||
# this method will either return a valid sale, or throw a RecurlyClientError or ActiveRecord validation error (save! failed)
|
||||
# it may return an nil sale if the JamTrack(s) specified by the shopping carts are already owned
|
||||
def self.order_jam_tracks(current_user, shopping_carts_jam_tracks)
|
||||
|
|
@ -139,58 +143,76 @@ module JamRuby
|
|||
sale = create_jam_track_sale(current_user)
|
||||
|
||||
if sale.valid?
|
||||
account = client.get_account(current_user)
|
||||
if account.present?
|
||||
if is_only_freebie(shopping_carts_jam_tracks)
|
||||
sale.process_jam_tracks(current_user, shopping_carts_jam_tracks, nil)
|
||||
|
||||
purge_pending_adjustments(account)
|
||||
sale.recurly_subtotal_in_cents = 0
|
||||
sale.recurly_tax_in_cents = 0
|
||||
sale.recurly_total_in_cents = 0
|
||||
sale.recurly_currency = 'USD'
|
||||
|
||||
created_adjustments = sale.process_jam_tracks(current_user, shopping_carts_jam_tracks, account)
|
||||
sale_line_item = sale.sale_line_items[0]
|
||||
sale_line_item.recurly_tax_in_cents = 0
|
||||
sale_line_item.recurly_total_in_cents = 0
|
||||
sale_line_item.recurly_currency = 'USD'
|
||||
sale_line_item.recurly_discount_in_cents = 0
|
||||
sale.save
|
||||
|
||||
# now invoice the sale ... almost done
|
||||
else
|
||||
|
||||
begin
|
||||
invoice = account.invoice!
|
||||
sale.recurly_invoice_id = invoice.uuid
|
||||
sale.recurly_invoice_number = invoice.invoice_number
|
||||
account = client.get_account(current_user)
|
||||
if account.present?
|
||||
|
||||
# now slap in all the real tax/purchase totals
|
||||
sale.recurly_subtotal_in_cents = invoice.subtotal_in_cents
|
||||
sale.recurly_tax_in_cents = invoice.tax_in_cents
|
||||
sale.recurly_total_in_cents = invoice.total_in_cents
|
||||
sale.recurly_currency = invoice.currency
|
||||
purge_pending_adjustments(account)
|
||||
|
||||
created_adjustments = sale.process_jam_tracks(current_user, shopping_carts_jam_tracks, account)
|
||||
|
||||
# now invoice the sale ... almost done
|
||||
|
||||
begin
|
||||
invoice = account.invoice!
|
||||
sale.recurly_invoice_id = invoice.uuid
|
||||
sale.recurly_invoice_number = invoice.invoice_number
|
||||
|
||||
# now slap in all the real tax/purchase totals
|
||||
sale.recurly_subtotal_in_cents = invoice.subtotal_in_cents
|
||||
sale.recurly_tax_in_cents = invoice.tax_in_cents
|
||||
sale.recurly_total_in_cents = invoice.total_in_cents
|
||||
sale.recurly_currency = invoice.currency
|
||||
|
||||
# and resolve against sale_line_items
|
||||
sale.sale_line_items.each do |sale_line_item|
|
||||
found_line_item = false
|
||||
invoice.line_items.each do |line_item|
|
||||
if line_item.uuid == sale_line_item.recurly_adjustment_uuid
|
||||
sale_line_item.recurly_tax_in_cents = line_item.tax_in_cents
|
||||
sale_line_item.recurly_total_in_cents =line_item.total_in_cents
|
||||
sale_line_item.recurly_currency = line_item.currency
|
||||
sale_line_item.recurly_discount_in_cents = line_item.discount_in_cents
|
||||
found_line_item = true
|
||||
break
|
||||
end
|
||||
|
||||
# and resolve against sale_line_items
|
||||
sale.sale_line_items.each do |sale_line_item|
|
||||
found_line_item = false
|
||||
invoice.line_items.each do |line_item|
|
||||
if line_item.uuid == sale_line_item.recurly_adjustment_uuid
|
||||
sale_line_item.recurly_tax_in_cents = line_item.tax_in_cents
|
||||
sale_line_item.recurly_total_in_cents =line_item.total_in_cents
|
||||
sale_line_item.recurly_currency = line_item.currency
|
||||
sale_line_item.recurly_discount_in_cents = line_item.discount_in_cents
|
||||
found_line_item = true
|
||||
break
|
||||
end
|
||||
|
||||
if !found_line_item
|
||||
@@log.error("can't find line item #{sale_line_item.recurly_adjustment_uuid}")
|
||||
puts "CANT FIND LINE ITEM"
|
||||
end
|
||||
end
|
||||
|
||||
if !found_line_item
|
||||
@@log.error("can't find line item #{sale_line_item.recurly_adjustment_uuid}")
|
||||
puts "CANT FIND LINE ITEM"
|
||||
unless sale.save
|
||||
raise RecurlyClientError, "Invalid sale (at end)."
|
||||
end
|
||||
rescue Recurly::Resource::Invalid => e
|
||||
# this exception is thrown by invoice! if the invoice is invalid
|
||||
sale.rollback_adjustments(current_user, created_adjustments)
|
||||
sale = nil
|
||||
raise ActiveRecord::Rollback # kill all db activity, but don't break outside logic
|
||||
end
|
||||
|
||||
unless sale.save
|
||||
raise RecurlyClientError, "Invalid sale (at end)."
|
||||
end
|
||||
rescue Recurly::Resource::Invalid => e
|
||||
# this exception is thrown by invoice! if the invoice is invalid
|
||||
sale.rollback_adjustments(current_user, created_adjustments)
|
||||
sale = nil
|
||||
raise ActiveRecord::Rollback # kill all db activity, but don't break outside logic
|
||||
else
|
||||
raise RecurlyClientError, "Could not find account to place order."
|
||||
end
|
||||
else
|
||||
raise RecurlyClientError, "Could not find account to place order."
|
||||
end
|
||||
else
|
||||
raise RecurlyClientError, "Invalid sale."
|
||||
|
|
@ -238,30 +260,33 @@ module JamRuby
|
|||
return
|
||||
end
|
||||
|
||||
# ask the shopping cart to create the correct Recurly adjustment attributes for a JamTrack
|
||||
adjustments = shopping_cart.create_adjustment_attributes(current_user)
|
||||
if account
|
||||
# ask the shopping cart to create the correct Recurly adjustment attributes for a JamTrack
|
||||
adjustments = shopping_cart.create_adjustment_attributes(current_user)
|
||||
|
||||
adjustments.each do |adjustment|
|
||||
adjustments.each do |adjustment|
|
||||
|
||||
# create the adjustment at Recurly (this may not look like it, but it is a REST API)
|
||||
created_adjustment = account.adjustments.new(adjustment)
|
||||
created_adjustment.save
|
||||
# create the adjustment at Recurly (this may not look like it, but it is a REST API)
|
||||
created_adjustment = account.adjustments.new(adjustment)
|
||||
created_adjustment.save
|
||||
|
||||
# if the adjustment could not be made, bail
|
||||
raise RecurlyClientError.new(created_adjustment.errors) if created_adjustment.errors.any?
|
||||
# if the adjustment could not be made, bail
|
||||
raise RecurlyClientError.new(created_adjustment.errors) if created_adjustment.errors.any?
|
||||
|
||||
# keep track of adjustments we created for this order, in case we have to roll them back
|
||||
created_adjustments << created_adjustment
|
||||
# keep track of adjustments we created for this order, in case we have to roll them back
|
||||
created_adjustments << created_adjustment
|
||||
|
||||
if ShoppingCart.is_product_purchase?(adjustment)
|
||||
# this was a normal product adjustment, so track it as such
|
||||
recurly_adjustment_uuid = created_adjustment.uuid
|
||||
else
|
||||
# this was a 'credit' adjustment, so track it as such
|
||||
recurly_adjustment_credit_uuid = created_adjustment.uuid
|
||||
if ShoppingCart.is_product_purchase?(adjustment)
|
||||
# this was a normal product adjustment, so track it as such
|
||||
recurly_adjustment_uuid = created_adjustment.uuid
|
||||
else
|
||||
# this was a 'credit' adjustment, so track it as such
|
||||
recurly_adjustment_credit_uuid = created_adjustment.uuid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# create one sale line item for every jam track
|
||||
sale_line_item = SaleLineItem.create_from_shopping_cart(self, shopping_cart, nil, recurly_adjustment_uuid, recurly_adjustment_credit_uuid)
|
||||
|
||||
|
|
@ -279,7 +304,11 @@ module JamRuby
|
|||
end
|
||||
|
||||
# also if the purchase was a free one, then update the user record to no longer allow redeemed jamtracks
|
||||
User.where(id: current_user.id).update_all(has_redeemable_jamtrack: false) if shopping_cart.free?
|
||||
if shopping_cart.free?
|
||||
User.where(id: current_user.id).update_all(has_redeemable_jamtrack: false)
|
||||
current_user.has_redeemable_jamtrack = false # make sure model reflects the truth
|
||||
end
|
||||
|
||||
|
||||
# this can't go in the block above, as it's here to fix bad subscription UUIDs in an update path
|
||||
if jam_track_right.recurly_adjustment_uuid != recurly_adjustment_uuid
|
||||
|
|
|
|||
|
|
@ -152,6 +152,12 @@ module JamRuby
|
|||
def self.add_jam_track_to_cart(any_user, jam_track)
|
||||
cart = nil
|
||||
ShoppingCart.transaction do
|
||||
|
||||
if any_user.has_redeemable_jamtrack
|
||||
# if you still have a freebie available to you, or if you are an anonymous user, we make sure there is nothing else in your shopping cart
|
||||
any_user.destroy_all_shopping_carts
|
||||
end
|
||||
|
||||
mark_redeem = ShoppingCart.user_has_redeemable_jam_track?(any_user)
|
||||
cart = ShoppingCart.create(any_user, jam_track, 1, mark_redeem)
|
||||
end
|
||||
|
|
@ -173,7 +179,13 @@ module JamRuby
|
|||
carts[0].save
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def port(user, anonymous_user)
|
||||
|
||||
ShoppingCart.transaction do
|
||||
move_to_user(user, anonymous_user, anonymous_user.shopping_carts)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -6,6 +6,7 @@ module JamRuby
|
|||
# we use it to figure out what to do with the user after they signup
|
||||
class SignupHint < ActiveRecord::Base
|
||||
|
||||
belongs_to :jam_track, class_name: 'JamRuby::JamTrack'
|
||||
|
||||
belongs_to :user, class_name: 'JamRuby::User'
|
||||
|
||||
|
|
@ -23,6 +24,7 @@ module JamRuby
|
|||
hint.anonymous_user_id = anonymous_user.id
|
||||
hint.redirect_location = options[:redirect_location] if options.has_key?(:redirect_location)
|
||||
hint.want_jamblaster = options[:want_jamblaster] if options.has_key?(:want_jamblaster)
|
||||
#hint.jam_track = JamTrack.find(options[:jam_track]) if options.has_key?(:jam_track)
|
||||
hint.expires_at = 15.minutes.from_now
|
||||
hint.save
|
||||
hint
|
||||
|
|
|
|||
|
|
@ -991,6 +991,7 @@ module JamRuby
|
|||
recaptcha_failed = options[:recaptcha_failed]
|
||||
any_user = options[:any_user]
|
||||
reuse_card = options[:reuse_card]
|
||||
signup_hint = options[:signup_hint]
|
||||
|
||||
user = User.new
|
||||
|
||||
|
|
@ -1056,8 +1057,6 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
unless fb_signup.nil?
|
||||
user.update_fb_authorization(fb_signup)
|
||||
|
||||
|
|
@ -1110,6 +1109,18 @@ module JamRuby
|
|||
|
||||
user.save
|
||||
|
||||
# if the user has just one, free jamtrack in their shopping cart, and it matches the signup hint, then auto-buy it
|
||||
# only_freebie_in_cart =
|
||||
# signup_hint &&
|
||||
# signup_hint.jam_track &&
|
||||
# user.shopping_carts.length == 1 &&
|
||||
# user.shopping_carts[0].cart_product == signup_hint.jam_track &&
|
||||
# user.shopping_carts[0].product_info[:free]
|
||||
#
|
||||
# if only_freebie_in_cart
|
||||
# Sale.place_order(user, user.shopping_carts)
|
||||
# end
|
||||
|
||||
user.errors.add("recaptcha", "verification failed") if recaptcha_failed
|
||||
|
||||
if user.errors.any?
|
||||
|
|
@ -1615,6 +1626,21 @@ module JamRuby
|
|||
APP_CONFIG.admin_root_url + "/admin/jam_track_rights?q[user_id_equals]=#{id}&commit=Filter&order=created_at DESC"
|
||||
end
|
||||
|
||||
# these are signup attributes that we default to when not presenting the typical form @ /signup
|
||||
def self.musician_defaults(remote_ip, confirmation_url, any_user, options)
|
||||
options = options || {}
|
||||
options[:remote_ip] = remote_ip
|
||||
options[:birth_date] = nil
|
||||
options[:instruments] = [{:instrument_id => 'other', :proficiency_level => 1, :priority => 1}]
|
||||
options[:musician] = true
|
||||
options[:skip_recaptcha] = true
|
||||
options[:invited_user] = nil
|
||||
options[:fb_signup] = nil
|
||||
options[:signup_confirm_url] = confirmation_url
|
||||
options[:any_user] = any_user
|
||||
options
|
||||
end
|
||||
|
||||
private
|
||||
def create_remember_token
|
||||
self.remember_token = SecureRandom.urlsafe_base64
|
||||
|
|
|
|||
|
|
@ -208,5 +208,125 @@ describe JamTrackRight do
|
|||
end
|
||||
end
|
||||
|
||||
describe "guard_against_fraud" do
|
||||
let(:user) {FactoryGirl.create(:user)}
|
||||
let(:other) {FactoryGirl.create(:user)}
|
||||
let(:first_fingerprint) { {all: 'all', running: 'running' } }
|
||||
let(:new_fingerprint) { {all: 'all_2', running: 'running' } }
|
||||
let(:remote_ip) {'1.1.1.1'}
|
||||
let(:jam_track_right) { FactoryGirl.create(:jam_track_right, user: user, redeemed: true, redeemed_and_fingerprinted: false) }
|
||||
let(:jam_track_right_purchased) { FactoryGirl.create(:jam_track_right, user: user, redeemed: false, redeemed_and_fingerprinted: false) }
|
||||
let(:jam_track_right_other) { FactoryGirl.create(:jam_track_right, user: other, redeemed: true, redeemed_and_fingerprinted: false) }
|
||||
let(:jam_track_right_other_purchased) { FactoryGirl.create(:jam_track_right, user: other, redeemed: false, redeemed_and_fingerprinted: false) }
|
||||
|
||||
it "denies no current_user" do
|
||||
jam_track_right.guard_against_fraud(nil, first_fingerprint, remote_ip).should eq('no user specified')
|
||||
end
|
||||
|
||||
it "denies no fingerprint" do
|
||||
jam_track_right.guard_against_fraud(user, nil, remote_ip).should eq('no fingerprint specified')
|
||||
end
|
||||
|
||||
it "allows redemption (success)" do
|
||||
jam_track_right.guard_against_fraud(user, first_fingerprint, remote_ip).should be_nil
|
||||
jam_track_right.valid?.should be_true
|
||||
jam_track_right.redeemed_and_fingerprinted.should be_true
|
||||
|
||||
|
||||
mf = MachineFingerprint.find_by_fingerprint(first_fingerprint[:all])
|
||||
mf.user.should eq(user)
|
||||
mf.fingerprint.should eq(first_fingerprint[:all])
|
||||
mf.when_taken.should eq(MachineFingerprint::TAKEN_ON_SUCCESSFUL_DOWNLOAD)
|
||||
mf.print_type.should eq(MachineFingerprint::PRINT_TYPE_ALL)
|
||||
mf.jam_track_right.should eq(jam_track_right)
|
||||
|
||||
mf = MachineFingerprint.find_by_fingerprint(first_fingerprint[:running])
|
||||
mf.user.should eq(user)
|
||||
mf.fingerprint.should eq(first_fingerprint[:running])
|
||||
mf.when_taken.should eq(MachineFingerprint::TAKEN_ON_SUCCESSFUL_DOWNLOAD)
|
||||
mf.print_type.should eq(MachineFingerprint::PRINT_TYPE_ACTIVE)
|
||||
mf.jam_track_right.should eq(jam_track_right)
|
||||
end
|
||||
|
||||
it "ignores already successfully redeemed" do
|
||||
jam_track_right.redeemed_and_fingerprinted = true
|
||||
jam_track_right.save!
|
||||
|
||||
jam_track_right.guard_against_fraud(user, new_fingerprint, remote_ip).should be_nil
|
||||
jam_track_right.valid?.should be_true
|
||||
|
||||
# and no new fingerprints
|
||||
MachineFingerprint.count.should eq(0)
|
||||
end
|
||||
|
||||
it "ignores already normally purchased" do
|
||||
jam_track_right.guard_against_fraud(user, first_fingerprint, remote_ip)
|
||||
MachineFingerprint.count.should eq(2)
|
||||
|
||||
jam_track_right_purchased.guard_against_fraud(user, new_fingerprint, remote_ip).should be_nil
|
||||
jam_track_right_purchased.valid?.should be_true
|
||||
jam_track_right_purchased.redeemed_and_fingerprinted.should be_false # fingerprint should not be set on normal purchase
|
||||
|
||||
jam_track_right.redeemed_and_fingerprinted.should be_true # should still be redeemed_and fingerprinted; just checking for weird side-effects
|
||||
|
||||
# no new fingerprints
|
||||
MachineFingerprint.count.should eq(2)
|
||||
end
|
||||
|
||||
it "protects against re-using fingerprint across users (conflicts on all fp)" do
|
||||
jam_track_right.guard_against_fraud(user, first_fingerprint, remote_ip).should be_nil
|
||||
MachineFingerprint.count.should eq(2)
|
||||
first_fingerprint[:running] = 'running_2'
|
||||
jam_track_right_other.guard_against_fraud(other, first_fingerprint, remote_ip).should eq("other user has 'all' fingerprint")
|
||||
|
||||
mf = MachineFingerprint.find_by_fingerprint(first_fingerprint[:running])
|
||||
mf.user.should eq(other)
|
||||
mf.fingerprint.should eq(first_fingerprint[:running])
|
||||
mf.when_taken.should eq(MachineFingerprint::TAKEN_ON_FRAUD_CONFLICT)
|
||||
mf.print_type.should eq(MachineFingerprint::PRINT_TYPE_ACTIVE)
|
||||
mf.jam_track_right.should eq(jam_track_right_other)
|
||||
MachineFingerprint.count.should eq(3)
|
||||
end
|
||||
|
||||
it "protects against re-using fingerprint across users (conflicts on running fp)" do
|
||||
jam_track_right.guard_against_fraud(user, first_fingerprint, remote_ip).should be_nil
|
||||
MachineFingerprint.count.should eq(2)
|
||||
first_fingerprint[:all] = 'all_2'
|
||||
jam_track_right_other.guard_against_fraud(other, first_fingerprint, remote_ip).should eq("other user has 'running' fingerprint")
|
||||
|
||||
mf = MachineFingerprint.find_by_fingerprint(first_fingerprint[:all])
|
||||
mf.user.should eq(other)
|
||||
mf.fingerprint.should eq(first_fingerprint[:all])
|
||||
mf.when_taken.should eq(MachineFingerprint::TAKEN_ON_FRAUD_CONFLICT)
|
||||
mf.print_type.should eq(MachineFingerprint::PRINT_TYPE_ALL)
|
||||
mf.jam_track_right.should eq(jam_track_right_other)
|
||||
MachineFingerprint.count.should eq(3)
|
||||
end
|
||||
|
||||
# if you try to buy a regular jamtrack with a fingerprint belonging to another user? so what. you paid for it
|
||||
it "allows re-use of fingerprint if jamtrack is a normal purchase" do
|
||||
jam_track_right.guard_against_fraud(user, first_fingerprint, remote_ip).should be_nil
|
||||
MachineFingerprint.count.should eq(2)
|
||||
jam_track_right_other_purchased.guard_against_fraud(other, first_fingerprint, remote_ip).should be_nil
|
||||
MachineFingerprint.count.should eq(2)
|
||||
end
|
||||
|
||||
it "stops you from redeeming two jamtracks" do
|
||||
right1 = FactoryGirl.create(:jam_track_right, user: user, redeemed: true, redeemed_and_fingerprinted: true)
|
||||
jam_track_right.guard_against_fraud(user, first_fingerprint, remote_ip).should eq('already redeemed another')
|
||||
MachineFingerprint.count.should eq(0)
|
||||
end
|
||||
|
||||
it "let's you download a free jamtrack if you have a second but undownloaded free one" do
|
||||
right1 = FactoryGirl.create(:jam_track_right, user: user, redeemed: true, redeemed_and_fingerprinted: false)
|
||||
jam_track_right.guard_against_fraud(user, first_fingerprint, remote_ip).should be_nil
|
||||
MachineFingerprint.count.should eq(2)
|
||||
|
||||
right1.guard_against_fraud(user, first_fingerprint, remote_ip).should eq('already redeemed another')
|
||||
MachineFingerprint.count.should eq(2)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -87,9 +87,9 @@ describe Sale do
|
|||
|
||||
sales.should eq(user.sales)
|
||||
sale = sales[0]
|
||||
sale.recurly_invoice_id.should_not be_nil
|
||||
sale.recurly_invoice_id.should be_nil
|
||||
|
||||
sale.recurly_subtotal_in_cents.should eq(jam_track_price_in_cents)
|
||||
sale.recurly_subtotal_in_cents.should eq(0)
|
||||
sale.recurly_tax_in_cents.should eq(0)
|
||||
sale.recurly_total_in_cents.should eq(0)
|
||||
sale.recurly_currency.should eq('USD')
|
||||
|
|
@ -97,7 +97,7 @@ describe Sale do
|
|||
sale.sale_line_items.length.should == 1
|
||||
sale_line_item = sale.sale_line_items[0]
|
||||
sale_line_item.recurly_tax_in_cents.should eq(0)
|
||||
sale_line_item.recurly_total_in_cents.should eq(jam_track_price_in_cents)
|
||||
sale_line_item.recurly_total_in_cents.should eq(0)
|
||||
sale_line_item.recurly_currency.should eq('USD')
|
||||
sale_line_item.recurly_discount_in_cents.should eq(0)
|
||||
sale_line_item.product_type.should eq(JamTrack::PRODUCT_TYPE)
|
||||
|
|
@ -109,8 +109,8 @@ describe Sale do
|
|||
sale_line_item.recurly_plan_code.should eq(jamtrack.plan_code)
|
||||
sale_line_item.product_id.should eq(jamtrack.id)
|
||||
sale_line_item.recurly_subscription_uuid.should be_nil
|
||||
sale_line_item.recurly_adjustment_uuid.should_not be_nil
|
||||
sale_line_item.recurly_adjustment_credit_uuid.should_not be_nil
|
||||
sale_line_item.recurly_adjustment_uuid.should be_nil
|
||||
sale_line_item.recurly_adjustment_credit_uuid.should be_nil
|
||||
sale_line_item.recurly_adjustment_uuid.should eq(user.jam_track_rights.last.recurly_adjustment_uuid)
|
||||
sale_line_item.recurly_adjustment_credit_uuid.should eq(user.jam_track_rights.last.recurly_adjustment_credit_uuid)
|
||||
|
||||
|
|
@ -118,31 +118,11 @@ describe Sale do
|
|||
recurly_account = client.get_account(user)
|
||||
adjustments = recurly_account.adjustments
|
||||
adjustments.should_not be_nil
|
||||
adjustments.should have(2).items
|
||||
free_purchase= adjustments[0]
|
||||
free_purchase.unit_amount_in_cents.should eq((jamtrack.price * 100).to_i)
|
||||
free_purchase.accounting_code.should eq(ShoppingCart::PURCHASE_FREE)
|
||||
free_purchase.description.should eq("JamTrack: " + jamtrack.name)
|
||||
free_purchase.state.should eq('invoiced')
|
||||
free_purchase.uuid.should eq(sale_line_item.recurly_adjustment_uuid)
|
||||
|
||||
free_credit = adjustments[1]
|
||||
free_credit.unit_amount_in_cents.should eq(-(jamtrack.price * 100).to_i)
|
||||
free_credit.accounting_code.should eq(ShoppingCart::PURCHASE_FREE_CREDIT)
|
||||
free_credit.description.should eq("JamTrack: " + jamtrack.name + " (Credit)")
|
||||
free_credit.state.should eq('invoiced')
|
||||
free_credit.uuid.should eq(sale_line_item.recurly_adjustment_credit_uuid)
|
||||
adjustments.should have(0).items
|
||||
|
||||
invoices = recurly_account.invoices
|
||||
invoices.should have(1).items
|
||||
invoice = invoices[0]
|
||||
invoice.uuid.should eq(sale.recurly_invoice_id)
|
||||
invoice.line_items.should have(2).items # should have both adjustments associated
|
||||
invoice.line_items[0].should eq(free_credit)
|
||||
invoice.line_items[1].should eq(free_purchase)
|
||||
invoice.subtotal_in_cents.should eq((jamtrack.price * 100).to_i)
|
||||
invoice.total_in_cents.should eq(0)
|
||||
invoice.state.should eq('collected')
|
||||
invoices.should have(0).items
|
||||
|
||||
|
||||
# verify jam_track_rights data
|
||||
user.jam_track_rights.should_not be_nil
|
||||
|
|
@ -238,7 +218,7 @@ describe Sale do
|
|||
# also, verify that no earlier adjustments were affected
|
||||
recurly_account = client.get_account(user)
|
||||
adjustments = recurly_account.adjustments
|
||||
adjustments.should have(2).items
|
||||
adjustments.should have(0).items # because the only successful purchase was a freebie, there should be no recurly adjustments
|
||||
end
|
||||
|
||||
# this test counts on the fact that two adjustments are made when buying a free JamTrack
|
||||
|
|
@ -246,13 +226,13 @@ describe Sale do
|
|||
# we can see if the first one is ultimately destroyed
|
||||
it "rolls back created adjustments if error" do
|
||||
|
||||
shopping_cart = ShoppingCart.create user, jamtrack, 1, true
|
||||
shopping_cart = ShoppingCart.create user, jamtrack, 1, false
|
||||
|
||||
# grab the real response; we will modify it to make a nil accounting code
|
||||
adjustment_attrs = shopping_cart.create_adjustment_attributes(user)
|
||||
client.find_or_create_account(user, billing_info)
|
||||
|
||||
adjustment_attrs[1][:unit_amount_in_cents] = nil # invalid amount
|
||||
adjustment_attrs[0][:unit_amount_in_cents] = nil # invalid amount
|
||||
ShoppingCart.any_instance.stub(:create_adjustment_attributes).and_return(adjustment_attrs)
|
||||
|
||||
expect { Sale.place_order(user, [shopping_cart]) }.to raise_error(JamRuby::RecurlyClientError)
|
||||
|
|
@ -265,7 +245,7 @@ describe Sale do
|
|||
end
|
||||
|
||||
it "rolls back adjustments created before the order" do
|
||||
shopping_cart = ShoppingCart.create user, jamtrack, 1, true
|
||||
shopping_cart = ShoppingCart.create user, jamtrack, 1, false
|
||||
client.find_or_create_account(user, billing_info)
|
||||
|
||||
# create a single adjustment on the account
|
||||
|
|
@ -281,7 +261,7 @@ describe Sale do
|
|||
|
||||
recurly_account = client.get_account(user)
|
||||
adjustments = recurly_account.adjustments
|
||||
adjustments.should have(2).items # two adjustments are created for a free jamtrack; that should be all there is
|
||||
adjustments.should have(1).items # two adjustments are created for a free jamtrack; that should be all there is
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -21,34 +21,36 @@ describe ShoppingCart do
|
|||
user.shopping_carts[0].quantity.should == 1
|
||||
end
|
||||
|
||||
|
||||
it "maintains only one fre JamTrack in ShoppingCart" do
|
||||
cart1 = ShoppingCart.add_jam_track_to_cart(user, jam_track)
|
||||
cart1.should_not be_nil
|
||||
cart1.errors.any?.should be_false
|
||||
user.reload
|
||||
cart2 = ShoppingCart.add_jam_track_to_cart(user, jam_track)
|
||||
cart2.errors.any?.should be_false
|
||||
user.reload
|
||||
user.shopping_carts.length.should eq(1)
|
||||
cart3 = ShoppingCart.add_jam_track_to_cart(user, jam_track2)
|
||||
cart3.errors.any?.should be_false
|
||||
user.reload
|
||||
user.shopping_carts.length.should eq(1)
|
||||
end
|
||||
|
||||
it "should not add duplicate JamTrack to ShoppingCart" do
|
||||
user.has_redeemable_jamtrack = false
|
||||
user.save!
|
||||
cart1 = ShoppingCart.add_jam_track_to_cart(user, jam_track)
|
||||
cart1.should_not be_nil
|
||||
cart1.errors.any?.should be_false
|
||||
user.reload
|
||||
cart2 = ShoppingCart.add_jam_track_to_cart(user, jam_track)
|
||||
cart2.errors.any?.should be_true
|
||||
|
||||
end
|
||||
|
||||
describe "redeemable behavior" do
|
||||
it "adds redeemable item to shopping cart" do
|
||||
|
||||
user.has_redeemable_jamtrack.should be_true
|
||||
|
||||
# first item added to shopping cart should be marked for redemption
|
||||
cart = ShoppingCart.add_jam_track_to_cart(user, jam_track)
|
||||
cart.marked_for_redeem.should eq(1)
|
||||
|
||||
# but the second item should not
|
||||
|
||||
user.reload
|
||||
|
||||
cart = ShoppingCart.add_jam_track_to_cart(user, jam_track2)
|
||||
cart.marked_for_redeem.should eq(0)
|
||||
end
|
||||
|
||||
it "removes redeemable item to shopping cart" do
|
||||
it "removes redeemable item to shopping cart (maintains only one in cart)" do
|
||||
|
||||
user.has_redeemable_jamtrack.should be_true
|
||||
cart1 = ShoppingCart.add_jam_track_to_cart(user, jam_track)
|
||||
|
|
@ -58,12 +60,12 @@ describe ShoppingCart do
|
|||
cart2.should_not be_nil
|
||||
|
||||
cart1.marked_for_redeem.should eq(1)
|
||||
cart2.marked_for_redeem.should eq(0)
|
||||
cart2.marked_for_redeem.should eq(1)
|
||||
ShoppingCart.remove_jam_track_from_cart(user, jam_track)
|
||||
|
||||
user.shopping_carts.length.should eq(1)
|
||||
user.shopping_carts.length.should eq(0)
|
||||
cart2.reload
|
||||
cart1.marked_for_redeem.should eq(1)
|
||||
cart2.marked_for_redeem.should eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ require 'spec_helper'
|
|||
|
||||
describe SignupHint do
|
||||
|
||||
let(:user) {AnonymousUser.new(SecureRandom.uuid)}
|
||||
let(:user) {AnonymousUser.new(SecureRandom.uuid, nil)}
|
||||
|
||||
describe "refresh_by_anoymous_user" do
|
||||
it "creates" do
|
||||
|
|
|
|||
|
|
@ -194,6 +194,10 @@ def app_config
|
|||
'blah'
|
||||
end
|
||||
|
||||
def error_on_fraud
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def audiomixer_workspace_path
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 8.7 KiB |
|
|
@ -48,6 +48,10 @@
|
|||
//= require utils
|
||||
//= require subscription_utils
|
||||
//= require custom_controls
|
||||
//= require web/signup_helper
|
||||
//= require web/signin_helper
|
||||
//= require web/signin
|
||||
//= require web/tracking
|
||||
//= require_directory .
|
||||
//= require_directory ./dialog
|
||||
//= require_directory ./wizard
|
||||
|
|
|
|||
|
|
@ -481,7 +481,7 @@
|
|||
$('#band-profile-social-link').unbind('click').click(renderSocial);
|
||||
|
||||
$("#btn-edit-band-profile").unbind('click').click(function() {
|
||||
context.location = "/client#/band/setup/" + bandId + '/step1';
|
||||
context.location = "/client#/band/setup/" + bandId + '/step0';
|
||||
return false;
|
||||
});
|
||||
$("#btn-edit-band-info").unbind('click').click(function() {
|
||||
|
|
|
|||
|
|
@ -22,8 +22,56 @@
|
|||
var nilOptionText = 'n/a';
|
||||
var bandId = '';
|
||||
var friendInput=null;
|
||||
|
||||
// TODO: Use a single variable for a mutually exclusive option:
|
||||
var step1, step2;
|
||||
var isSaving = false;
|
||||
var currentStep = 0;
|
||||
var STEPS_COUNT=5;
|
||||
|
||||
function navBack() {
|
||||
if (currentStep>0) {
|
||||
saveBand(function() {
|
||||
currentStep--
|
||||
renderCurrentPage()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function navCancel() {
|
||||
resetForm()
|
||||
window.history.go(-1)
|
||||
return false
|
||||
}
|
||||
|
||||
function navNext() {
|
||||
if (currentStep<STEPS_COUNT-1) {
|
||||
saveBand(function(band) {
|
||||
currentStep++
|
||||
renderCurrentPage()
|
||||
})
|
||||
} else {
|
||||
saveBand(function(band) {
|
||||
resetForm()
|
||||
showProfile(band.id);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function renderCurrentPange() {
|
||||
$(".band-step").addClass("hidden")
|
||||
$("#band-setup-step-" + currentStep).removeClass("hidden")
|
||||
if(currentStep==0) {
|
||||
$("#btn-band-setup-back").addClass("hidden")
|
||||
$("#btn-band-setup-next").removeClass("hidden").html("SAVE & NEXT")
|
||||
} else if(currentStep<STEPS_COUNT-1) {
|
||||
$("#btn-band-setup-back").removeClass("hidden")
|
||||
$("#btn-band-setup-next").removeClass("hidden").html("SAVE & NEXT")
|
||||
} else {
|
||||
$("#btn-band-setup-back").removeClass("hidden")
|
||||
$("#btn-band-setup-next").removeClass("hidden").html("SAVE & FINISH")
|
||||
}
|
||||
}
|
||||
|
||||
function is_new_record() {
|
||||
return bandId.length == 0;
|
||||
|
|
@ -93,7 +141,6 @@
|
|||
removeErrors();
|
||||
|
||||
var band = buildBand();
|
||||
|
||||
return rest.validateBand(band);
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +170,13 @@
|
|||
band.city = $("#band-city").val();
|
||||
band.state = $("#band-region").val();
|
||||
band.country = $("#band-country").val();
|
||||
band.genres = getSelectedGenres();
|
||||
|
||||
if (step2) {
|
||||
band.genres = getSelectedGenres();
|
||||
band.validate_genres = true
|
||||
} else {
|
||||
band.validate_genres = false
|
||||
}
|
||||
return band;
|
||||
}
|
||||
|
||||
|
|
@ -131,64 +184,35 @@
|
|||
context.location = "/client#/bandProfile/" + band_id;
|
||||
}
|
||||
|
||||
function saveBand() {
|
||||
if (isSaving) return;
|
||||
isSaving = true;
|
||||
function saveInvitations() {
|
||||
if (0 < $('#selected-friends-band .invitation').length) {
|
||||
createBandInvitations(response.id, function () {
|
||||
showProfile(response.id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function saveBand(saveFn) {
|
||||
unbindNavButtons()
|
||||
var band = buildBand()
|
||||
|
||||
if (is_new_record()) {
|
||||
rest.createBand(band)
|
||||
.done(function (response) {
|
||||
isSaving = false;
|
||||
if (0 < $('#selected-friends-band .invitation').length) {
|
||||
createBandInvitations(response.id, function () {
|
||||
showProfile(response.id);
|
||||
});
|
||||
} else
|
||||
showProfile(response.id);
|
||||
})
|
||||
.fail(function (jqXHR) {
|
||||
isSaving = false;
|
||||
var saveBandFn = (is_new_record()) ? rest.createBand : rest.updateBand
|
||||
saveBandFn(band)
|
||||
.done(function (response) {
|
||||
saveInvitations()
|
||||
saveFn(band)
|
||||
})
|
||||
.fail(function (jqXHR) {
|
||||
if(jqXHR.status == 422) {
|
||||
renderErrors(JSON.parse(jqXHR.responseText))
|
||||
} else {
|
||||
app.notifyServerError(jqXHR, "Unable to create band")
|
||||
});
|
||||
;
|
||||
}
|
||||
else {
|
||||
band.id = bandId;
|
||||
if (!step1 && !step2){
|
||||
rest.updateBand(band)
|
||||
.done(function (response) {
|
||||
isSaving = false;
|
||||
createBandInvitations(band.id, function () {
|
||||
showProfile(band.id);
|
||||
});
|
||||
}).fail(function (jqXHR) {
|
||||
isSaving = false;
|
||||
app.notifyServerError(jqXHR, "Unable to create band")
|
||||
});
|
||||
} else {
|
||||
if (step1) {
|
||||
rest.updateBand(band)
|
||||
.done(function (response) {
|
||||
isSaving = false;
|
||||
app.notifyAlert('Band Information', 'Your changes have been saved');
|
||||
}).fail(function (jqXHR) {
|
||||
isSaving = false;
|
||||
app.notifyServerError(jqXHR, "Unable to update band")
|
||||
});
|
||||
} else if (step2) {
|
||||
isSaving = false;
|
||||
if (0 < $('#selected-friends-band .invitation').length) {
|
||||
createBandInvitations(bandId, function () {
|
||||
app.notifyAlert('Band Members', 'Your invitations have been sent');
|
||||
showProfile(bandId);
|
||||
});
|
||||
} else
|
||||
showProfile(bandId);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.always(function (jqXHR) {
|
||||
bindNavButtons()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function createBandInvitations(bandId, onComplete) {
|
||||
|
|
@ -219,68 +243,41 @@
|
|||
function beforeShow(data) {
|
||||
inviteMusiciansUtil.clearSelections();
|
||||
bandId = data.id == 'new' ? '' : data.id;
|
||||
|
||||
step1 = step2 = false;
|
||||
if ('step2'==data['d']) {
|
||||
step2 = true;
|
||||
delete data['d'];
|
||||
} else if ('step1'==data['d']){
|
||||
step1 = true;
|
||||
currentStep=0
|
||||
if (data['d']) {
|
||||
var stepNum = data['d'].substring(4)
|
||||
if(stepNum) {
|
||||
currentStep=stepNum
|
||||
delete data['d'];
|
||||
resetForm();
|
||||
}
|
||||
}
|
||||
resetForm();
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
inviteMusiciansUtil.loadFriends();
|
||||
|
||||
if (!is_new_record()) {
|
||||
$("#band-setup-title").html("edit band");
|
||||
$("#btn-band-setup-save").html("SAVE CHANGES");
|
||||
$("#band-change-photo").html('Upload band photo.');
|
||||
$('#tdBandPhoto').css('visibility', 'visible');
|
||||
|
||||
$('.band-photo').removeClass("hidden")
|
||||
|
||||
// retrieve and initialize band profile data points
|
||||
loadBandDetails();
|
||||
|
||||
if (step2) {
|
||||
$("#band-setup-step-2").show();
|
||||
$("#band-setup-step-1").hide();
|
||||
$('.band-setup-text-step2').each(function(idx) { $(this).hide(); });
|
||||
$('#btn-band-setup-back').text('CANCEL');
|
||||
$('#btn-band-setup-save').text('SEND INVITATIONS');
|
||||
|
||||
} else if (step1) {
|
||||
$("#band-setup-step-1").show();
|
||||
$("#band-setup-step-2").hide();
|
||||
$('.band-setup-text-step1').each(function(idx) { $(this).hide(); });
|
||||
$('#btn-band-setup-next').text('SAVE');
|
||||
}
|
||||
if (! step1 && ! step2) {
|
||||
$('#btn-band-setup-next').text('NEXT');
|
||||
$('#btn-band-setup-back').text('CANCEL');
|
||||
$('#btn-band-setup-save').text('CREATE BAND');
|
||||
$('.band-setup-text-step1').each(function(idx) { $(this).show(); });
|
||||
$('.band-setup-text-step2').each(function(idx) { $(this).show(); });
|
||||
}
|
||||
}
|
||||
else {
|
||||
loadBandDetails();
|
||||
} else {
|
||||
loadGenres();
|
||||
|
||||
rest.getResolvedLocation()
|
||||
.done(function (location) {
|
||||
loadCountries(location.country, function () {
|
||||
loadRegions(location.region, function () {
|
||||
loadCities(location.city);
|
||||
});
|
||||
// Load geo settings:
|
||||
rest.getResolvedLocation().done(function (location) {
|
||||
loadCountries(location.country, function () {
|
||||
loadRegions(location.region, function () {
|
||||
loadCities(location.city);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$("#band-setup-title").html("set up band");
|
||||
$("#btn-band-setup-save").html("CREATE BAND");
|
||||
$('#tdBandPhoto').css('visibility', 'hidden'); // can't upload photo when going through initial setup
|
||||
$('.band-photo').addClass("hidden")
|
||||
}
|
||||
renderCurrentPange()
|
||||
}
|
||||
|
||||
function loadBandDetails() {
|
||||
|
|
@ -459,52 +456,49 @@
|
|||
$(evt.currentTarget).closest('.invitation').remove();
|
||||
}
|
||||
|
||||
function bindNavButtons() {
|
||||
$('#btn-band-setup-back').on("click", function (e) {
|
||||
e.stopPropagation()
|
||||
navBack()
|
||||
return false
|
||||
})
|
||||
|
||||
$('#btn-band-setup-cancel').on("click", function (e) {
|
||||
e.stopPropagation()
|
||||
navCancel()
|
||||
return false
|
||||
})
|
||||
|
||||
$('#btn-band-setup-next').on("click", function (e) {
|
||||
e.stopPropagation()
|
||||
navNext()
|
||||
return false
|
||||
})
|
||||
|
||||
$('#btn-band-setup-back').removeClass("disabled")
|
||||
$('#btn-band-setup-cancel').removeClass("disabled")
|
||||
$('#btn-band-setup-next').removeClass("disabled")
|
||||
}
|
||||
|
||||
function unbindNavButtons() {
|
||||
$('#btn-band-setup-back').off("click")
|
||||
$('#btn-band-setup-cancel').off("click")
|
||||
$('#btn-band-setup-next').off("click")
|
||||
$('#btn-band-setup-back').addClass("disabled")
|
||||
$('#btn-band-setup-cancel').addClass("disabled")
|
||||
$('#btn-band-setup-next').addClass("disabled")
|
||||
}
|
||||
|
||||
function events() {
|
||||
$('#selected-band-invitees').on("click", ".invitation a", removeInvitation);
|
||||
|
||||
bindNavButtons();
|
||||
|
||||
// friend input focus
|
||||
$('#band-invitee-input').focus(function () {
|
||||
$(this).val('');
|
||||
});
|
||||
|
||||
$('#btn-band-setup-cancel').click(function () {
|
||||
resetForm();
|
||||
window.history.go(-1);
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#btn-band-setup-next').click(function () {
|
||||
validateGeneralInfo()
|
||||
.done(function (response) {
|
||||
if (!step1 && !step2) {
|
||||
$("#band-setup-step-2").show();
|
||||
$("#band-setup-step-1").hide();
|
||||
} else if (step1) {
|
||||
saveBand();
|
||||
}
|
||||
})
|
||||
.fail(function (jqXHR) {
|
||||
if(jqXHR.status == 422) {
|
||||
renderErrors(JSON.parse(jqXHR.responseText))
|
||||
}
|
||||
else {
|
||||
app.notifyServerError(jqXHR, "Unable to validate band")
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#btn-band-setup-back').click(function () {
|
||||
if (!step2) {
|
||||
$("#band-setup-step-1").show();
|
||||
$("#band-setup-step-2").hide();
|
||||
} else {
|
||||
showProfile(bandId);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
$('#btn-band-setup-save').click(saveBand);
|
||||
|
||||
});
|
||||
|
||||
$('#band-country').on('change', function (evt) {
|
||||
evt.stopPropagation();
|
||||
loadRegions();
|
||||
|
|
@ -519,7 +513,7 @@
|
|||
});
|
||||
|
||||
$('#band-change-photo').click(navigateToBandPhoto);
|
||||
$('#band-setup .avatar-profile').click(navigateToBandPhoto);
|
||||
$('#band-setup .band-avatar-profile').click(navigateToBandPhoto);
|
||||
|
||||
$('div[layout-id="band/setup"] .btn-email-invitation').click(function () {
|
||||
invitationDialog.showEmailDialog();
|
||||
|
|
@ -554,6 +548,5 @@
|
|||
this.initialize = initialize;
|
||||
this.afterShow = afterShow;
|
||||
return this;
|
||||
};
|
||||
|
||||
};
|
||||
})(window, jQuery);
|
||||
|
|
@ -560,20 +560,6 @@
|
|||
$screen.find("#payment-info-next").on('click', next);
|
||||
}
|
||||
|
||||
function beforeShowOrder() {
|
||||
step = 3;
|
||||
renderNavigation();
|
||||
populateOrderPage();
|
||||
}
|
||||
|
||||
|
||||
function populateOrderPage() {
|
||||
|
||||
rest.getShoppingCarts()
|
||||
.done(renderOrderPage)
|
||||
.fail(app.ajaxError);
|
||||
}
|
||||
|
||||
function toggleShippingAsBilling(e) {
|
||||
e.preventDefault();
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
var $contentHolder = null;
|
||||
var $btnNext = null;
|
||||
var $btnFacebook = null;
|
||||
var checkoutUtils = context.JK.CheckoutUtilsInstance;
|
||||
|
||||
function beforeShow(data) {
|
||||
renderNavigation();
|
||||
|
|
@ -96,9 +97,23 @@
|
|||
$signinBtn.text('TRYING...').addClass('disabled')
|
||||
|
||||
rest.login({email: email, password: password, remember_me: true})
|
||||
.done(function() {
|
||||
window.location = '/client#/checkoutPayment'
|
||||
window.location.reload();
|
||||
.done(function(user) {
|
||||
// now determine where we should send the user
|
||||
rest.getShoppingCarts()
|
||||
.done(function(carts) {
|
||||
if(checkoutUtils.hasOneFreeItemInShoppingCart(carts)) {
|
||||
window.location = '/client#/redeemComplete'
|
||||
window.location.reload();
|
||||
}
|
||||
else {
|
||||
window.location = '/client#/checkoutPayment'
|
||||
window.location.reload();
|
||||
}
|
||||
})
|
||||
.fail(function() {
|
||||
window.location = '/client#/jamtrackBrowse'
|
||||
window.location.reload();
|
||||
})
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
if(jqXHR.status == 422) {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,16 @@ class CheckoutUtils
|
|||
getLastPurchase: () =>
|
||||
return @lastPurchaseResponse
|
||||
|
||||
hasOneFreeItemInShoppingCart: (carts) =>
|
||||
|
||||
if carts.length == 0
|
||||
# nothing is in the user's shopping cart. They shouldn't be here.
|
||||
return false;
|
||||
else if carts.length > 1
|
||||
# the user has multiple items in their shopping cart. They shouldn't be here.
|
||||
return false;
|
||||
|
||||
return carts[0].product_info.free
|
||||
|
||||
# global instance
|
||||
context.JK.CheckoutUtilsInstance = new CheckoutUtils()
|
||||
|
|
@ -195,7 +195,7 @@
|
|||
var obj = {
|
||||
method: 'feed',
|
||||
link: signupUrl,
|
||||
picture: 'http://www.jamkazam.com/assets/web/logo-256.png',
|
||||
picture: 'https://www.jamkazam.com/assets/web/logo-256.png',
|
||||
name: 'Join me on JamKazam',
|
||||
caption: 'Play live music in real-time sessions with others over the Internet, as if in the same room.',
|
||||
description: '',
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@
|
|||
rest.openJamTrack({id: context.JK.CurrentSessionModel.id(), jam_track_id: jamTrack.id})
|
||||
.done(function(response) {
|
||||
$dialog.data('result', {success:true, jamTrack: jamTrack})
|
||||
context.JK.CurrentSessionModel.updateSession(response);
|
||||
app.layout.closeDialog('open-jam-track-dialog');
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
|
|
|
|||
|
|
@ -11,11 +11,21 @@
|
|||
var dialogId = '#signin-dialog';
|
||||
var $dialog = null;
|
||||
var signinHelper = null;
|
||||
var redirectTo = null;
|
||||
|
||||
|
||||
function beforeShow() {
|
||||
function beforeShow(args) {
|
||||
logger.debug("showing login form")
|
||||
signinHelper.reset();
|
||||
if(args.redirect_to) {
|
||||
redirectTo = "/client#/redeemComplete"
|
||||
}
|
||||
else {
|
||||
redirectTo = null;
|
||||
}
|
||||
if(redirectTo) {
|
||||
logger.debug("setting redirect to in login dialog")
|
||||
}
|
||||
signinHelper.reset(redirectTo);
|
||||
}
|
||||
|
||||
function afterShow() {
|
||||
|
|
@ -24,6 +34,7 @@
|
|||
|
||||
function afterHide() {
|
||||
logger.debug("hiding login form")
|
||||
redirectTo = null;
|
||||
}
|
||||
|
||||
function initialize(){
|
||||
|
|
|
|||
|
|
@ -206,6 +206,8 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
|
|||
showInitial: () =>
|
||||
@logger.debug("showing #{@state.name}")
|
||||
@sampleRate = context.jamClient.GetSampleRate()
|
||||
@fingerprint = context.jamClient.SessionGetMacHash()
|
||||
logger.debug("fingerprint: ", @fingerprint)
|
||||
@sampleRateForFilename = if @sampleRate == 48 then '48' else '44'
|
||||
@attempts = @attempts + 1
|
||||
this.expectTransition()
|
||||
|
|
@ -450,7 +452,7 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
|
|||
@attemptedEnqueue = true
|
||||
@ajaxEnqueueAborted = false
|
||||
|
||||
@rest.enqueueJamTrack({id: @jamTrack.id, sample_rate: @sampleRate})
|
||||
@rest.enqueueJamTrack({id: @jamTrack.id, sample_rate: @sampleRate, fingerprint: @fingerprint})
|
||||
.done(this.processEnqueueJamTrack)
|
||||
.fail(this.processEnqueueJamTrackFail)
|
||||
|
||||
|
|
@ -474,9 +476,24 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
|
|||
else
|
||||
@logger.debug("DownloadJamTrack: ignoring processEnqueueJamTrack response")
|
||||
|
||||
processEnqueueJamTrackFail: () =>
|
||||
displayUIForGuard:(response) =>
|
||||
display = switch response.message
|
||||
when 'no user specified' then 'Please log back in.'
|
||||
when 'no fingerprint specified' then 'There was a problem communicating between client and server. Please restart JamKazam.'
|
||||
when 'no all fingerprint specified' then 'There was a problem communicating between client and server. Please restart JamKazam.'
|
||||
when 'no running fingerprint specified' then 'There was a problem communicating between client and server. Please restart JamKazam.'
|
||||
when 'already redeemed another' then "It appears you have already redeemed your one free JamTrack for your household. We are sorry, but we cannot let you download this JamTrack free. If you believe this is an error, please contact us at support@jamkazam.com."
|
||||
when "other user has 'all' fingerprint" then "It appears you have already redeemed your one free JamTrack for your household. We are sorry, but we cannot let you download this JamTrack free. If you believe this is an error, please contact us at support@jamkazam.com."
|
||||
when "other user has 'running' fingerprint" then "It appears you have already redeemed your one free JamTrack for your household. We are sorry, but we cannot let you download this JamTrack free. If you believe this is an error, please contact us at support@jamkazam.com."
|
||||
else "Something went wrong #{response.message}. Please restart JamKazam"
|
||||
|
||||
processEnqueueJamTrackFail: (jqXHR) =>
|
||||
unless @ajaxEnqueueAborted
|
||||
this.transitionError("enqueue-error", "Unable to ask the server to build your JamTrack.")
|
||||
if jqXHR.status == 403
|
||||
display = this.displayUIForGuard(JSON.parse(jqXHR.responseText))
|
||||
this.transitionError("enqueue-error", display)
|
||||
else
|
||||
this.transitionError("enqueue-error", "Unable to ask the server to build your JamTrack.")
|
||||
else
|
||||
@logger.debug("DownloadJamTrack: ignoring processEnqueueJamTrackFail response")
|
||||
|
||||
|
|
|
|||
|
|
@ -210,6 +210,7 @@
|
|||
if (!userProfile.show_jamtrack_guide && userProfile.show_whats_next && userProfile.show_whats_next_count < 10 &&
|
||||
window.location.pathname.indexOf(gon.client_path) == 0 &&
|
||||
window.location.hash.indexOf('/checkout') == -1 &&
|
||||
window.location.hash.indexOf('/redeem') == -1 &&
|
||||
!app.layout.isDialogShowing('getting-started'))
|
||||
{
|
||||
app.layout.showDialog('getting-started');
|
||||
|
|
@ -229,8 +230,8 @@
|
|||
try {
|
||||
cookie = JSON.parse(cookie)
|
||||
|
||||
context.JK.signup = {}
|
||||
context.JK.signup = cookie
|
||||
context.JK.signupData = {}
|
||||
context.JK.signupData = cookie
|
||||
|
||||
$(function() {
|
||||
// ga() object isn't ready until the page is loaded
|
||||
|
|
|
|||
|
|
@ -1702,6 +1702,26 @@
|
|||
});
|
||||
}
|
||||
|
||||
function signup(data) {
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
url: '/api/users',
|
||||
dataType: "json",
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(data),
|
||||
});
|
||||
}
|
||||
|
||||
function portOverCarts() {
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
url: '/api/shopping_carts/port',
|
||||
dataType: "json",
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(data)
|
||||
})
|
||||
}
|
||||
|
||||
function createAlert(subject, data) {
|
||||
var message = {subject:subject};
|
||||
$.extend(message, data);
|
||||
|
|
@ -1870,6 +1890,8 @@
|
|||
this.playJamTrack = playJamTrack;
|
||||
this.createSignupHint = createSignupHint;
|
||||
this.createAlert = createAlert;
|
||||
this.signup = signup;
|
||||
this.portOverCarts = portOverCarts;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ context.JK.JamTrackPreview = class JamTrackPreview
|
|||
@EVENTS = context.JK.EVENTS
|
||||
@rest = context.JK.Rest()
|
||||
@logger = context.JK.logger
|
||||
@options = options || {master_shows_duration: false, color:'gray'}
|
||||
@options = options || {master_shows_duration: false, color:'gray', add_line_break: false}
|
||||
@app = app
|
||||
@jamTrack = jamTrack
|
||||
@jamTrackTrack = jamTrackTrack
|
||||
|
|
@ -56,17 +56,26 @@ context.JK.JamTrackPreview = class JamTrackPreview
|
|||
|
||||
if @jamTrackTrack.track_type == 'Track'
|
||||
part = "#{@jamTrackTrack.part}" if @jamTrackTrack.part? && @jamTrackTrack.part != instrumentDescription
|
||||
|
||||
@part.text("(#{part})") if part != ''
|
||||
else
|
||||
if @options.master_shows_duration
|
||||
duration = 'entire song'
|
||||
if @jamTrack.duration
|
||||
duration = "0:00 - #{context.JK.prettyPrintSeconds(@jamTrack.duration)}"
|
||||
part = duration
|
||||
else
|
||||
part = @jamTrack.name + ' by ' + @jamTrack.original_artist
|
||||
if @options.master_adds_line_break
|
||||
part = '"' + @jamTrack.name + '"' + ' by ' + @jamTrack.original_artist
|
||||
|
||||
@part.html("#{part}") if part != ''
|
||||
@part.addClass('adds-line-break')
|
||||
else
|
||||
|
||||
if @options.master_shows_duration
|
||||
duration = 'entire song'
|
||||
if @jamTrack.duration
|
||||
duration = "#{context.JK.prettyPrintSeconds(@jamTrack.duration)}"
|
||||
part = duration
|
||||
else
|
||||
part = @jamTrack.name + ' by ' + @jamTrack.original_artist
|
||||
|
||||
@part.text("(#{part})") if part != ''
|
||||
|
||||
|
||||
@part.text("(#{part})") if part != ''
|
||||
|
||||
if @jamTrackTrack.preview_mp3_url?
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ context.JK.JamTrackScreen=class JamTrackScreen
|
|||
this.refresh()
|
||||
|
||||
afterShow:(data) =>
|
||||
context.JK.Tracking.jamtrackBrowseTrack(@app)
|
||||
|
||||
beforeHide: () =>
|
||||
this.clearResults();
|
||||
|
|
@ -192,9 +193,23 @@ context.JK.JamTrackScreen=class JamTrackScreen
|
|||
|
||||
addToCartJamtrack:(e) =>
|
||||
e.preventDefault()
|
||||
params = id: $(e.target).attr('data-jamtrack-id')
|
||||
$target = $(e.target)
|
||||
params = id: $target.attr('data-jamtrack-id')
|
||||
isFree = $(e.target).is('.is_free')
|
||||
|
||||
rest.addJamtrackToShoppingCart(params).done((response) =>
|
||||
context.location = '/client#/shoppingCart'
|
||||
if(isFree)
|
||||
if context.JK.currentUserId?
|
||||
alert("TODO")
|
||||
context.JK.currentUserFreeJamTrack = true # make sure the user sees no more free notices
|
||||
context.location = '/client#/redeemComplete'
|
||||
else
|
||||
# now make a rest call to buy it
|
||||
context.location = '/client#/redeemSignup'
|
||||
|
||||
else
|
||||
context.location = '/client#/shoppingCart'
|
||||
|
||||
).fail @app.ajaxError
|
||||
|
||||
licenseUSWhy:(e) =>
|
||||
|
|
@ -211,15 +226,15 @@ context.JK.JamTrackScreen=class JamTrackScreen
|
|||
|
||||
if expand
|
||||
trackElement.find('.extra').removeClass('hidden')
|
||||
detailArrow.html('hide tracks <a class="details-arrow arrow-up-orange"></a>')
|
||||
detailArrow.html('hide tracks <a class="details-arrow arrow-up"></a>')
|
||||
for track in jamTrack.tracks
|
||||
trackElement.find("[jamtrack-track-id='#{track.id}']").removeClass('hidden')
|
||||
else
|
||||
trackElement.find('.extra').addClass('hidden')
|
||||
detailArrow.html('preview all tracks <a class="details-arrow arrow-down-orange"></a>')
|
||||
detailArrow.html('show all tracks <a class="details-arrow arrow-down"></a>')
|
||||
count = 0
|
||||
for track in jamTrack.tracks
|
||||
if count < 2
|
||||
if count < 6
|
||||
trackElement.find("[jamtrack-track-id='#{track.id}']").removeClass('hidden')
|
||||
else
|
||||
trackElement.find("[jamtrack-track-id='#{track.id}']").addClass('hidden')
|
||||
|
|
@ -281,14 +296,15 @@ context.JK.JamTrackScreen=class JamTrackScreen
|
|||
if track.part != ''
|
||||
track.instrument_desc += ' (' + track.part + ')'
|
||||
|
||||
free_state = if gon.global.one_free_jamtrack_per_user then 'free' else 'non-free'
|
||||
if @user
|
||||
free_state = if @user.free_jamtrack then 'free' else 'non-free'
|
||||
free_state = if context.JK.currentUserFreeJamTrack then 'free' else 'non-free'
|
||||
|
||||
is_free = free_state == 'free'
|
||||
|
||||
options =
|
||||
jamtrack: trackRow
|
||||
expanded: false
|
||||
free_state: free_state
|
||||
free_state: free_state,
|
||||
is_free: is_free
|
||||
@jamtrackItem = $(context._.template($('#template-jamtrack').html(), options, variable: 'data'))
|
||||
that.renderJamtrack(@jamtrackItem, jamtrack)
|
||||
that.registerEvents(@jamtrackItem)
|
||||
|
|
|
|||
|
|
@ -930,8 +930,8 @@
|
|||
bandId: val.id,
|
||||
biography: val.biography,
|
||||
profile_url: "/client#/bandProfile/" + val.id,
|
||||
band_edit_url: "/client#/band/setup/" + val.id + '/step1',
|
||||
band_member_url: "/client#/band/setup/" + val.id + '/step2',
|
||||
band_edit_url: "/client#/band/setup/" + val.id + '/step0',
|
||||
band_member_url: "/client#/band/setup/" + val.id + '/step4',
|
||||
avatar_url: context.JK.resolveBandAvatarUrl(val.photo_url),
|
||||
name: val.name,
|
||||
location: val.location,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,263 @@
|
|||
(function (context, $) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.RedeemCompleteScreen = function (app) {
|
||||
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
var jamTrackUtils = context.JK.JamTrackUtils;
|
||||
var checkoutUtils = context.JK.CheckoutUtilsInstance;
|
||||
|
||||
var $screen = null;
|
||||
var $navigation = null;
|
||||
var $templatePurchasedJamTrack = null;
|
||||
var $thanksPanel = null;
|
||||
var $jamTrackInBrowser = null;
|
||||
var $jamTrackInClient = null;
|
||||
var $purchasedJamTrack = null;
|
||||
var $purchasedJamTrackHeader = null;
|
||||
var $purchasedJamTracks = null;
|
||||
var userDetail = null;
|
||||
var step = null;
|
||||
var downloadJamTracks = [];
|
||||
var purchasedJamTracks = null;
|
||||
var purchasedJamTrackIterator = 0;
|
||||
var $backBtn = null;
|
||||
var $downloadApplicationLink = null;
|
||||
var $noPurchasesPrompt = null;
|
||||
var shoppingCartItem = null;
|
||||
|
||||
|
||||
function beforeShow() {
|
||||
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
$noPurchasesPrompt.addClass('hidden')
|
||||
$purchasedJamTracks.empty()
|
||||
$thanksPanel.addClass("hidden")
|
||||
$purchasedJamTrackHeader.attr('status', 'in-progress')
|
||||
$jamTrackInBrowser.addClass('hidden')
|
||||
$jamTrackInClient.addClass('hidden')
|
||||
|
||||
|
||||
// if there is no current user, but it apperas we have a login cookie, just refresh
|
||||
if(!context.JK.currentUserId && $.cookie('remember_token')) {
|
||||
window.location.reload();
|
||||
}
|
||||
else {
|
||||
redeemJamTrack()
|
||||
}
|
||||
|
||||
//prepThanks()
|
||||
}
|
||||
|
||||
function handleShoppingCartResponse(carts) {
|
||||
|
||||
if(!checkoutUtils.hasOneFreeItemInShoppingCart(carts)) {
|
||||
// the user has multiple items in their shopping cart. They shouldn't be here.
|
||||
logger.error("invalid access of redeemComplete page")
|
||||
window.location = '/client#/jamtrackBrowse'
|
||||
}
|
||||
else {
|
||||
// ok, we have one, free item. save it for
|
||||
shoppingCartItem = carts[0];
|
||||
|
||||
rest.placeOrder()
|
||||
.done(function(purchaseResponse) {
|
||||
context.JK.currentUserFreeJamTrack = false // make sure the user sees no more free notices without having to do a full page refresh
|
||||
|
||||
checkoutUtils.setLastPurchase(purchaseResponse)
|
||||
jamTrackUtils.checkShoppingCart()
|
||||
//app.refreshUser() // this only causes grief in tests for some reason, and with currentUserFreeJamTrack = false above, this is probably now unnecessary
|
||||
|
||||
prepThanks();
|
||||
})
|
||||
.fail(function() {
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function redeemJamTrack() {
|
||||
rest.getShoppingCarts()
|
||||
.done(handleShoppingCartResponse)
|
||||
.fail(app.ajaxError);
|
||||
|
||||
}
|
||||
|
||||
function beforeHide() {
|
||||
if(downloadJamTracks) {
|
||||
context._.each(downloadJamTracks, function(downloadJamTrack) {
|
||||
downloadJamTrack.destroy();
|
||||
downloadJamTrack.root.remove();
|
||||
})
|
||||
|
||||
downloadJamTracks = [];
|
||||
}
|
||||
purchasedJamTracks = null;
|
||||
purchasedJamTrackIterator = 0;
|
||||
}
|
||||
|
||||
function prepThanks() {
|
||||
showThanks();
|
||||
}
|
||||
|
||||
function showThanks(purchaseResponse) {
|
||||
|
||||
|
||||
var purchaseResponse = checkoutUtils.getLastPurchase();
|
||||
|
||||
if(!purchaseResponse || purchaseResponse.length == 0) {
|
||||
// user got to this page with no context
|
||||
logger.debug("no purchases found; nothing to show")
|
||||
$noPurchasesPrompt.removeClass('hidden')
|
||||
}
|
||||
else {
|
||||
if(gon.isNativeClient) {
|
||||
$jamTrackInClient.removeClass('hidden')
|
||||
}
|
||||
else {
|
||||
$jamTrackInBrowser.removeClass('hidden');
|
||||
}
|
||||
$thanksPanel.removeClass('hidden')
|
||||
handleJamTracksPurchased(purchaseResponse.jam_tracks)
|
||||
}
|
||||
}
|
||||
|
||||
function handleJamTracksPurchased(jamTracks) {
|
||||
// were any JamTracks purchased?
|
||||
var jamTracksPurchased = jamTracks && jamTracks.length > 0;
|
||||
if(jamTracksPurchased) {
|
||||
if(gon.isNativeClient) {
|
||||
$jamTrackInClient.removeClass('hidden')
|
||||
context.JK.GA.virtualPageView('/redeemInClient');
|
||||
startDownloadJamTracks(jamTracks)
|
||||
}
|
||||
else {
|
||||
$jamTrackInBrowser.removeClass('hidden');
|
||||
|
||||
app.user().done(function(user) {
|
||||
// relative to 1 day ago (24 * 60 * 60 * 1000)
|
||||
if(new Date(user.created_at).getTime() < new Date().getTime() - 86400000) {
|
||||
logger.debug("existing user recorded")
|
||||
context.JK.GA.virtualPageView('/redeemInBrowserExistingUser');
|
||||
}
|
||||
else {
|
||||
logger.debug("new user recorded")
|
||||
context.JK.GA.virtualPageView('/redeemInBrowserNewUser');
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
app.user().done(function(user) {
|
||||
if(!user.first_downloaded_client_at) {
|
||||
$downloadApplicationLink.removeClass('hidden')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startDownloadJamTracks(jamTracks) {
|
||||
// there can be multiple purchased JamTracks, so we cycle through them
|
||||
|
||||
purchasedJamTracks = jamTracks;
|
||||
|
||||
// populate list of jamtracks purchased, that we will iterate through graphically
|
||||
context._.each(jamTracks, function(jamTrack) {
|
||||
var downloadJamTrack = new context.JK.DownloadJamTrack(app, jamTrack, 'small');
|
||||
var $purchasedJamTrack = $(context._.template(
|
||||
$templatePurchasedJamTrack.html(),
|
||||
jamTrack,
|
||||
{variable: 'data'}
|
||||
));
|
||||
|
||||
$purchasedJamTracks.append($purchasedJamTrack)
|
||||
|
||||
// show it on the page
|
||||
$purchasedJamTrack.append(downloadJamTrack.root)
|
||||
|
||||
downloadJamTracks.push(downloadJamTrack)
|
||||
})
|
||||
|
||||
iteratePurchasedJamTracks();
|
||||
}
|
||||
|
||||
function iteratePurchasedJamTracks() {
|
||||
if(purchasedJamTrackIterator < purchasedJamTracks.length ) {
|
||||
var downloadJamTrack = downloadJamTracks[purchasedJamTrackIterator++];
|
||||
|
||||
// make sure the 'purchasing JamTrack' section can be seen
|
||||
$purchasedJamTrack.removeClass('hidden');
|
||||
|
||||
// the widget indicates when it gets to any transition; we can hide it once it reaches completion
|
||||
$(downloadJamTrack).on(EVENTS.JAMTRACK_DOWNLOADER_STATE_CHANGED, function(e, data) {
|
||||
|
||||
if(data.state == downloadJamTrack.states.synchronized) {
|
||||
logger.debug("jamtrack " + downloadJamTrack.jamTrack.name + " synchronized;")
|
||||
//downloadJamTrack.root.remove();
|
||||
downloadJamTrack.destroy();
|
||||
|
||||
// go to the next JamTrack
|
||||
iteratePurchasedJamTracks()
|
||||
}
|
||||
})
|
||||
|
||||
logger.debug("jamtrack " + downloadJamTrack.jamTrack.name + " downloader initializing")
|
||||
|
||||
// kick off the download JamTrack process
|
||||
downloadJamTrack.init()
|
||||
|
||||
// XXX style-test code
|
||||
// downloadJamTrack.transitionError("package-error", "The server failed to create your package.")
|
||||
|
||||
}
|
||||
else {
|
||||
logger.debug("done iterating over purchased JamTracks")
|
||||
$purchasedJamTrackHeader.attr('status', 'done')
|
||||
}
|
||||
}
|
||||
|
||||
function events() {
|
||||
$backBtn.on('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
context.location = '/client#/jamtrackBrowse'
|
||||
})
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow,
|
||||
'beforeHide': beforeHide
|
||||
};
|
||||
app.bindScreen('redeemComplete', screenBindings);
|
||||
|
||||
$screen = $("#redeemCompleteScreen");
|
||||
$templatePurchasedJamTrack = $('#template-purchased-jam-track');
|
||||
$thanksPanel = $screen.find(".thanks-panel");
|
||||
$jamTrackInBrowser = $screen.find(".jam-tracks-in-browser");
|
||||
$jamTrackInClient = $screen.find(".jam-tracks-in-client");
|
||||
$purchasedJamTrack = $thanksPanel.find(".thanks-detail.purchased-jam-track");
|
||||
$purchasedJamTrackHeader = $purchasedJamTrack.find(".purchased-jam-track-header");
|
||||
$purchasedJamTracks = $purchasedJamTrack.find(".purchased-list")
|
||||
$backBtn = $screen.find('.back');
|
||||
$downloadApplicationLink = $screen.find('.download-jamkazam-wrapper');
|
||||
$noPurchasesPrompt = $screen.find('.no-purchases-prompt')
|
||||
|
||||
if ($screen.length == 0) throw "$screen must be specified";
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
||||
return this;
|
||||
}
|
||||
})
|
||||
(window, jQuery);
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
(function(context,$) {
|
||||
|
||||
"use strict";
|
||||
context.JK = context.JK || {};
|
||||
context.JK.RedeemSignUpScreen = function(app) {
|
||||
|
||||
var logger = context.JK.logger;
|
||||
var rest = context.JK.Rest();
|
||||
|
||||
var $screen = null;
|
||||
var $signupForm = null;
|
||||
var $self = $(this);
|
||||
var $email = null;
|
||||
var $password = null;
|
||||
var $firstName = null;
|
||||
var $lastName = null;
|
||||
|
||||
var $signupBtn = null;
|
||||
var $inputElements = null;
|
||||
var $contentHolder = null;
|
||||
var $btnNext = null;
|
||||
var $btnFacebook = null;
|
||||
var $termsOfServiceL = null;
|
||||
var $termsOfServiceR = null;
|
||||
var shoppingCartItem = null;
|
||||
var $jamtrackName = null;
|
||||
var $signinLink = null;
|
||||
|
||||
function beforeShow(data) {
|
||||
renderLoggedInState();
|
||||
}
|
||||
|
||||
function afterShow(data) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
function renderLoggedInState(){
|
||||
|
||||
if(isLoggedIn()) {
|
||||
$contentHolder.removeClass('not-signed-in').addClass('signed-in')
|
||||
}
|
||||
else {
|
||||
context.JK.Tracking.redeemSignupTrack(app)
|
||||
$jamtrackName.text('')
|
||||
$contentHolder.addClass('hidden')
|
||||
$contentHolder.removeClass('signed-in').addClass('not-signed-in')
|
||||
// now check that the user has one, and only one, free jamtrack in their shopping cart.
|
||||
rest.getShoppingCarts()
|
||||
.done(handleShoppingCartResponse)
|
||||
.fail(app.ajaxError);
|
||||
}
|
||||
}
|
||||
|
||||
function isLoggedIn() {
|
||||
return !!context.JK.currentUserId;
|
||||
}
|
||||
|
||||
function events() {
|
||||
$btnFacebook.on('click', onClickSignupFacebook)
|
||||
$signupForm.on('submit', signup)
|
||||
$signupBtn.on('click', signup)
|
||||
$signinLink.on('click', onSignin);
|
||||
}
|
||||
|
||||
function handleShoppingCartResponse(carts) {
|
||||
|
||||
if(carts.length == 0) {
|
||||
// nothing is in the user's shopping cart. They shouldn't be here.
|
||||
logger.error("invalid access of redeemJamTrack page")
|
||||
window.location = '/client#/jamtrackBrowse'
|
||||
}
|
||||
else if(carts.length > 1) {
|
||||
// the user has multiple items in their shopping cart. They shouldn't be here.
|
||||
logger.error("invalid access of redeemJamTrack page")
|
||||
window.location = '/client#/jamtrackBrowse'
|
||||
}
|
||||
else {
|
||||
var item = carts[0];
|
||||
|
||||
if(item.product_info.free) {
|
||||
// ok, we have one, free item. save it for
|
||||
shoppingCartItem = item;
|
||||
$jamtrackName.text('"' + shoppingCartItem.product_info.name + '"')
|
||||
$contentHolder.removeClass('hidden')
|
||||
}
|
||||
else {
|
||||
// the user has a non-free, single item in their basket. They shouldn't be here.
|
||||
logger.error("invalid access of redeemJamTrack page")
|
||||
window.location = '/client#/jamtrackBrowse'
|
||||
}
|
||||
}
|
||||
|
||||
var $latestCartHtml = "";
|
||||
|
||||
var any_in_us = false
|
||||
context._.each(carts, function(cart) {
|
||||
if(cart.product_info.sales_region == 'United States') {
|
||||
any_in_us = true
|
||||
}
|
||||
})
|
||||
}
|
||||
function onClickSignupFacebook(e) {
|
||||
// tos must already be clicked
|
||||
|
||||
$btnFacebook.addClass('disabled')
|
||||
|
||||
var $field = $termsOfServiceL.closest('.field')
|
||||
$field.find('.error-text').remove()
|
||||
|
||||
logger.debug("field, ", $field, $termsOfServiceL)
|
||||
if($termsOfServiceL.is(":checked")) {
|
||||
|
||||
rest.createSignupHint({redirect_location: '/client#/redeemComplete'})
|
||||
.done(function() {
|
||||
// send the user on to facebook signin
|
||||
window.location = $btnFacebook.attr('href');
|
||||
})
|
||||
.fail(function() {
|
||||
app.notify({text:"Facebook Signup is not working properly"});
|
||||
})
|
||||
.always(function() {
|
||||
$btnFacebook.removeClass('disabled')
|
||||
})
|
||||
}
|
||||
else {
|
||||
$field.addClass("error").addClass("transparent");
|
||||
$field.append("<ul class='error-text'><li>must be accepted</li></ul>");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function onSuccessfulSignin() {
|
||||
// the user has signed in;
|
||||
|
||||
// move all shopping carts from the anonymous user to the signed in user
|
||||
/*rest.portOverCarts()
|
||||
.done(function() {
|
||||
logger.debug("ported over carts")
|
||||
window.location = '/client#/redeemComplete'
|
||||
})
|
||||
.fail(function() {
|
||||
window.location.reload();
|
||||
})
|
||||
|
||||
*/
|
||||
window.location = '/client#/redeemComplete'
|
||||
}
|
||||
|
||||
function onSignin() {
|
||||
app.layout.showDialog('signin-dialog', {redirect_to:onSuccessfulSignin});
|
||||
return false;
|
||||
}
|
||||
|
||||
function signup() {
|
||||
if($signupBtn.is('.disabled')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// clear out previous errors
|
||||
$signupForm.find('.field.error').removeClass('error')
|
||||
$signupForm.find('ul.error-text').remove()
|
||||
|
||||
var email = $email.val();
|
||||
var password = $password.val();
|
||||
var first_name = $firstName.val();
|
||||
var last_name = $lastName.val();
|
||||
var terms = $termsOfServiceR.is(':checked')
|
||||
|
||||
$signupBtn.text('TRYING...').addClass('disabled')
|
||||
|
||||
|
||||
rest.signup({email: email, password: password, first_name: first_name, last_name: last_name, terms:terms})
|
||||
.done(function(response) {
|
||||
window.location = '/client#/redeemComplete'
|
||||
window.location.reload()
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
if(jqXHR.status == 422) {
|
||||
var response = JSON.parse(jqXHR.responseText)
|
||||
if(response.errors) {
|
||||
var $errors = context.JK.format_errors('first_name', response);
|
||||
if ($errors) $firstName.closest('.field').addClass('error').append($errors);
|
||||
|
||||
$errors = context.JK.format_errors('last_name', response);
|
||||
if ($errors) $lastName.closest('.field').addClass('error').append($errors);
|
||||
|
||||
$errors = context.JK.format_errors('password', response);
|
||||
if ($errors) $password.closest('.field').addClass('error').append($errors);
|
||||
|
||||
var $errors = context.JK.format_errors('email', response);
|
||||
if ($errors) $email.closest('.field').addClass('error').append($errors);
|
||||
|
||||
var $errors = context.JK.format_errors('terms_of_service', response);
|
||||
if ($errors) $termsOfServiceR.closest('.field').addClass('error').append($errors);
|
||||
}
|
||||
else {
|
||||
app.notify({title: 'Unknown Signup Error', text: jqXHR.responseText})
|
||||
}
|
||||
}
|
||||
else {
|
||||
app.notifyServerError(jqXHR, "Unable to Sign Up")
|
||||
}
|
||||
})
|
||||
.always(function() {
|
||||
$signupBtn.text('SIGNUP').removeClass('disabled')
|
||||
})
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function initialize() {
|
||||
var screenBindings = {
|
||||
'beforeShow': beforeShow,
|
||||
'afterShow': afterShow
|
||||
};
|
||||
app.bindScreen('redeemSignup', screenBindings);
|
||||
|
||||
$screen = $("#redeemSignupScreen");
|
||||
$signupForm = $screen.find(".signup-form");
|
||||
$signupBtn = $signupForm.find('.signup-submit');
|
||||
$email = $signupForm.find('input[name="email"]');
|
||||
$password = $signupForm.find('input[name="password"]');
|
||||
$firstName = $signupForm.find('input[name="first_name"]');
|
||||
$lastName = $signupForm.find('input[name="last_name"]');
|
||||
$inputElements = $signupForm.find('.input-elements');
|
||||
$contentHolder = $screen.find('.content-holder');
|
||||
$btnFacebook = $screen.find('.signup-facebook')
|
||||
$termsOfServiceL = $screen.find('.left-side .terms_of_service input[type="checkbox"]')
|
||||
$termsOfServiceR = $screen.find('.right-side .terms_of_service input[type="checkbox"]')
|
||||
$jamtrackName = $screen.find('.jamtrack-name');
|
||||
$signinLink = $screen.find('.signin')
|
||||
|
||||
if($screen.length == 0) throw "$screen must be specified";
|
||||
|
||||
events();
|
||||
}
|
||||
|
||||
this.initialize = initialize;
|
||||
|
||||
return this;
|
||||
}
|
||||
})(window,jQuery);
|
||||
|
|
@ -501,6 +501,7 @@
|
|||
rest.openJamTrack({id: context.JK.CurrentSessionModel.id(), jam_track_id: jamTrack.id})
|
||||
.done(function(response) {
|
||||
// now actually load the jamtrack
|
||||
context.JK.CurrentSessionModel.updateSession(response);
|
||||
loadJamTrack(jamTrack);
|
||||
})
|
||||
.fail(function(jqXHR) {
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@
|
|||
}
|
||||
// did I open up the current JamTrack?
|
||||
function selfOpenedJamTracks() {
|
||||
logger.debug("currentSession", currentSession)
|
||||
return currentSession && (currentSession.jam_track_initiator_id == context.JK.currentUserId)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,23 +30,35 @@
|
|||
function proceedCheckout(e) {
|
||||
e.preventDefault();
|
||||
|
||||
logger.debug("proceedCheckout")
|
||||
if (!context.JK.currentUserId) {
|
||||
logger.debug("proceeding to signin screen because there is no user")
|
||||
window.location = '/client#/checkoutSignin';
|
||||
}
|
||||
else {
|
||||
var user = app.currentUser();
|
||||
|
||||
if(user.has_recurly_account && user.reuse_card) {
|
||||
logger.debug("proceeding to checkout order screen because we have card info already")
|
||||
window.location = '/client#/checkoutOrder';
|
||||
if (context.JK.currentUserFreeJamTrack) {
|
||||
if(context.JK.currentUserId) {
|
||||
logger.debug("proceeding to redeem complete screen because user has a free jamtrack and is logged in")
|
||||
window.location = '/client#/redeemComplete'
|
||||
}
|
||||
else {
|
||||
logger.debug("proceeding to checkout payment screen because we do not have card info")
|
||||
window.location = '/client#/checkoutPayment';
|
||||
logger.debug("proceeding to redeem signup screen because user has a free jamtrack and is not logged in")
|
||||
window.location = '/client#/redeemSignup'
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!context.JK.currentUserId) {
|
||||
logger.debug("proceeding to signin screen because there is no user")
|
||||
window.location = '/client#/checkoutSignin';
|
||||
}
|
||||
else {
|
||||
var user = app.currentUser();
|
||||
|
||||
if(user.has_recurly_account && user.reuse_card) {
|
||||
logger.debug("proceeding to checkout order screen because we have card info already")
|
||||
window.location = '/client#/checkoutOrder';
|
||||
}
|
||||
else {
|
||||
logger.debug("proceeding to checkout payment screen because we do not have card info")
|
||||
window.location = '/client#/checkoutPayment';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function removeCart(e) {
|
||||
|
|
|
|||
|
|
@ -9,24 +9,32 @@
|
|||
var logger = context.JK.logger;
|
||||
var $page = null;
|
||||
var $jamtrack_name = null;
|
||||
var $jamtrack_band = null;
|
||||
var $previews = null;
|
||||
var $jamTracksButton = null;
|
||||
var $genericHeader = null;
|
||||
var $individualizedHeader = null;
|
||||
var $ctaJamTracksButton = null;
|
||||
|
||||
function fetchJamTrack() {
|
||||
rest.getJamTrack({plan_code: gon.jam_track_plan_code})
|
||||
rest.getJamTrackWithArtistInfo({plan_code: gon.jam_track_plan_code})
|
||||
.done(function (jam_track) {
|
||||
logger.debug("jam_track", jam_track)
|
||||
|
||||
if(!gon.just_previews) {
|
||||
if (gon.generic) {
|
||||
$genericHeader.removeClass('hidden');
|
||||
$jamTracksButton.attr('href', '/client#/jamtrackBrowse')
|
||||
$jamTracksButton.removeClass('hidden').text("Check out all 100+ JamTracks")
|
||||
|
||||
}
|
||||
else {
|
||||
$individualizedHeader.removeClass('hidden')
|
||||
$jamtrack_name.text(jam_track.name);
|
||||
$jamtrack_name.text('"' + jam_track.name + '"');
|
||||
$jamtrack_band.text(jam_track.original_artist)
|
||||
$jamTracksButton.attr('href', '/client?artist=' + jam_track.original_artist + '#/jamtrackBrowse')
|
||||
$jamTracksButton.removeClass('hidden').text("Preview all " + jam_track.band_jam_track_count + " of our " + jam_track.original_artist + " JamTracks")
|
||||
$ctaJamTracksButton.attr('href', '/client?artist=' + jam_track.original_artist + '#/jamtrackBrowse')
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -36,24 +44,29 @@
|
|||
|
||||
$previews.append($element);
|
||||
|
||||
new context.JK.JamTrackPreview(app, $element, jam_track, track, {master_shows_duration: false, color:'black'})
|
||||
new context.JK.JamTrackPreview(app, $element, jam_track, track, {master_shows_duration: false, color:'black', master_adds_line_break: true})
|
||||
})
|
||||
|
||||
$previews.append('<br clear = "all" />')
|
||||
|
||||
|
||||
})
|
||||
.fail(function () {
|
||||
app.notify({title: 'Unable to fetch JamTrack', text: "Please refresh the page or try again later."})
|
||||
})
|
||||
|
||||
}
|
||||
function initialize() {
|
||||
|
||||
$page = $('body')
|
||||
$jamtrack_name = $page.find('.jamtrack_name')
|
||||
$jamtrack_band = $page.find('.jamtrack_band')
|
||||
$previews = $page.find('.previews')
|
||||
$jamTracksButton = $page.find('.browse-jamtracks-wrapper .white-bordered-button')
|
||||
$jamTracksButton = $page.find('.browse-jamtracks')
|
||||
$ctaJamTracksButton = $page.find('.cta-free-jamtrack');
|
||||
$genericHeader = $page.find('h1.generic')
|
||||
$individualizedHeader = $page.find('h1.individualized')
|
||||
|
||||
context.JK.Tracking.adTrack(app)
|
||||
fetchJamTrack();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,27 +13,28 @@
|
|||
var $jamTrackNoun = null;
|
||||
var $previews = null;
|
||||
var $jamTracksButton = null;
|
||||
var $jamtrack_band = null;
|
||||
var $checkItOut = null;
|
||||
var $ctaJamTracksButton = null;
|
||||
|
||||
function fetchJamTrack() {
|
||||
rest.getJamTrackWithArtistInfo({plan_code: gon.jam_track_plan_code})
|
||||
.done(function (jam_track) {
|
||||
logger.debug("jam_track", jam_track)
|
||||
|
||||
$jamTrackBandInfo.text(jam_track.band_jam_track_count + ' ' + jam_track.original_artist);
|
||||
$jamtrack_band.text(jam_track.original_artist)
|
||||
$jamTracksButton.attr('href', '/client?artist=' + jam_track.original_artist + '#/jamtrackBrowse')
|
||||
$jamTracksButton.removeClass('hidden').text("Preview all " + jam_track.band_jam_track_count + " of our " + jam_track.original_artist + " JamTracks")
|
||||
$ctaJamTracksButton.attr('href', '/client?artist=' + jam_track.original_artist + '#/jamtrackBrowse')
|
||||
|
||||
|
||||
if(jam_track.band_jam_track_count == 1) {
|
||||
$jamTrackNoun.text('JamTrack')
|
||||
$checkItOut.text(', Check It Out!')
|
||||
}
|
||||
context._.each(jam_track.tracks, function (track) {
|
||||
|
||||
var $element = $('<div class="jam-track-preview-holder"></div>')
|
||||
|
||||
$previews.append($element);
|
||||
|
||||
new context.JK.JamTrackPreview(app, $element, jam_track, track, {master_shows_duration: false, color:'black'})
|
||||
new context.JK.JamTrackPreview(app, $element, jam_track, track, {master_shows_duration: false, color:'black', master_adds_line_break:true})
|
||||
})
|
||||
|
||||
$previews.append('<br clear = "all" />')
|
||||
|
|
@ -48,10 +49,11 @@
|
|||
$page = $('body')
|
||||
$jamTrackBandInfo = $page.find('.jamtrack_band_info')
|
||||
$previews = $page.find('.previews')
|
||||
$jamTracksButton = $page.find('.browse-jamtracks-wrapper .white-bordered-button')
|
||||
$jamTrackNoun = $page.find('.jamtrack_noun')
|
||||
$checkItOut = $page.find('.check-it-out')
|
||||
$jamtrack_band = $page.find('.jamtrack_band')
|
||||
$jamTracksButton = $page.find('.browse-jamtracks')
|
||||
$ctaJamTracksButton = $page.find('.cta-free-jamtrack');
|
||||
|
||||
context.JK.Tracking.adTrack(app)
|
||||
fetchJamTrack();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,21 +20,26 @@
|
|||
var $rememberMe = null;
|
||||
var useAjax = false;
|
||||
var EVENTS = context.JK.EVENTS;
|
||||
|
||||
function reset() {
|
||||
var argRedirectTo = null;
|
||||
|
||||
function reset(_redirectTo) {
|
||||
argRedirectTo = _redirectTo;
|
||||
clear();
|
||||
}
|
||||
|
||||
function clear() {
|
||||
$signinForm.removeClass('login-error')
|
||||
|
||||
$email.val('');
|
||||
$password.val('');
|
||||
$rememberMe.attr('checked', 'checked')
|
||||
}
|
||||
|
||||
function login() {
|
||||
var email = $email.val();
|
||||
var password = $password.val();
|
||||
var rememberMe = $rememberMe.is(':checked')
|
||||
|
||||
reset();
|
||||
clear();
|
||||
|
||||
$signinBtn.text('TRYING...');
|
||||
|
||||
|
|
@ -42,6 +47,15 @@
|
|||
.done(function() {
|
||||
//app.layout.closeDialog('signin-dialog')
|
||||
|
||||
if(argRedirectTo) {
|
||||
if(argRedirectTo instanceof Function) {
|
||||
argRedirectTo();
|
||||
}
|
||||
else {
|
||||
window.location.href = argRedirectTo;
|
||||
}
|
||||
return;
|
||||
}
|
||||
var redirectTo = $.QueryString['redirect-to'];
|
||||
if(redirectTo) {
|
||||
logger.debug("redirectTo:" + redirectTo);
|
||||
|
|
@ -68,7 +82,7 @@
|
|||
|
||||
function events() {
|
||||
$signinCancelBtn.click(function(e) {
|
||||
app.layout.closeDialog('signin-dialog');
|
||||
app.layout.closeDialog('signin-dialog', true);
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
|
||||
|
||||
$ = jQuery
|
||||
context = window
|
||||
context.JK ||= {};
|
||||
|
||||
class Tracking
|
||||
constructor: () ->
|
||||
@logger = context.JK.logger
|
||||
@rest = new context.JK.Rest();
|
||||
|
||||
adTrack: (app) =>
|
||||
utmSource = $.QueryString['utm_source']
|
||||
if utmSource == 'facebook-ads' || utmSource == 'google-ads' || utmSource == 'twitter-ads' || utmSource == 'affiliate' || utmSource == 'pr'
|
||||
if !context.jamClient.IsNativeClient()
|
||||
if context.JK.currentUserId?
|
||||
app.user().done( (user) =>
|
||||
# relative to 1 day ago (24 * 60 * 60 * 1000)
|
||||
if new Date(user.created_at).getTime() < new Date().getTime() - 86400000
|
||||
@logger.debug("existing user recorded")
|
||||
context.JK.GA.virtualPageView('/landing/jamtracks/existing-user/');
|
||||
else
|
||||
@logger.debug("new user recorded")
|
||||
context.JK.GA.virtualPageView('/landing/jamtracks/new-user/')
|
||||
)
|
||||
else
|
||||
@logger.debug("new user recorded")
|
||||
context.JK.GA.virtualPageView('/landing/jamtracks/new-user/')
|
||||
else
|
||||
@logger.debug("existing user recorded")
|
||||
context.JK.GA.virtualPageView('/landing/jamtracks/existing-user/');
|
||||
|
||||
jamtrackBrowseTrack: (app) =>
|
||||
if context.JK.currentUserId?
|
||||
app.user().done( (user) =>
|
||||
if context.jamClient.IsNativeClient()
|
||||
@logger.debug("client user recorded")
|
||||
context.JK.GA.virtualPageView('/client#/jamtrackBrowse/user-in-app')
|
||||
else
|
||||
if new Date(user.created_at).getTime() < new Date().getTime() - 86400000
|
||||
@logger.debug("existing user recorded")
|
||||
context.JK.GA.virtualPageView('/client#/jamtrackBrowse/existing-user')
|
||||
else
|
||||
@logger.debug("existing new recorded")
|
||||
context.JK.GA.virtualPageView('/client#/jamtrackBrowse/new-user')
|
||||
)
|
||||
else
|
||||
if context.jamClient.IsNativeClient()
|
||||
@logger.debug("client user recorded")
|
||||
context.JK.GA.virtualPageView('/client#/jamtrackBrowse/user-in-app')
|
||||
else
|
||||
@logger.debug("existing new recorded")
|
||||
context.JK.GA.virtualPageView('/client#/jamtrackBrowse/new-user')
|
||||
|
||||
|
||||
|
||||
redeemSignupTrack: (app) =>
|
||||
if context.JK.currentUserId?
|
||||
app.user().done( (user) =>
|
||||
if context.jamClient.IsNativeClient()
|
||||
@logger.debug("client user recorded")
|
||||
context.JK.GA.virtualPageView('/client#/redeemSignup/user-in-app')
|
||||
else
|
||||
if new Date(user.created_at).getTime() < new Date().getTime() - 86400000
|
||||
@logger.debug("existing existing recorded")
|
||||
context.JK.GA.virtualPageView('/client#/redeemSignup/existing-user')
|
||||
else
|
||||
@logger.debug("existing new recorded")
|
||||
context.JK.GA.virtualPageView('/client#/redeemSignup/new-user')
|
||||
)
|
||||
else
|
||||
if context.jamClient.IsNativeClient()
|
||||
@logger.debug("client user recorded")
|
||||
context.JK.GA.virtualPageView('/client#/redeemSignup/user-in-app')
|
||||
else
|
||||
@logger.debug("existing new recorded")
|
||||
context.JK.GA.virtualPageView('/client#/redeemSignup/new-user')
|
||||
|
||||
|
||||
context.JK.Tracking = new Tracking()
|
||||
|
||||
|
|
@ -62,6 +62,7 @@
|
|||
//= require web/session_info
|
||||
//= require web/recordings
|
||||
//= require web/home
|
||||
//= require web/tracking
|
||||
//= require web/individual_jamtrack
|
||||
//= require web/individual_jamtrack_band
|
||||
//= require fakeJamClient
|
||||
|
|
|
|||
|
|
@ -1,354 +1,373 @@
|
|||
@import "client/common.css.scss";
|
||||
|
||||
#band-setup, #band-profile {
|
||||
input, select, textarea {
|
||||
@include border_box_sizing;
|
||||
width: 100%;
|
||||
padding: 2px 4px 2px 2px;
|
||||
}
|
||||
|
||||
.band-setup-bio {
|
||||
height:90px;
|
||||
overflow:auto;
|
||||
}
|
||||
|
||||
.band-setup-genres {
|
||||
width:100%;
|
||||
height:90px;
|
||||
background-color:#c5c5c5;
|
||||
border:none;
|
||||
-webkit-box-shadow: inset 2px 2px 3px 0px #888;
|
||||
box-shadow: inset 2px 2px 3px 0px #888;
|
||||
color:#000;
|
||||
overflow:auto;
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
.band-setup-photo {
|
||||
|
||||
.avatar-space {
|
||||
color: $color2;
|
||||
margin: 20px;
|
||||
position:relative;
|
||||
min-height:300px;
|
||||
|
||||
img.preview_profile_avatar {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.spinner-large {
|
||||
width:300px;
|
||||
height:300px;
|
||||
line-height: 300px;
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
z-index: 2000; // to win over jcrop
|
||||
}
|
||||
|
||||
.no-avatar-space {
|
||||
border:1px dotted $color2;
|
||||
|
||||
color: $color2;
|
||||
width:300px;
|
||||
height:300px;
|
||||
line-height: 300px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
background-color:$ColorTextBoxBackground;
|
||||
|
||||
td.band-biography {
|
||||
height:100%;
|
||||
vertical-align: top;
|
||||
#band-biography {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.band-profile-header {
|
||||
padding:20px;
|
||||
height:120px;
|
||||
}
|
||||
|
||||
.band-profile-header h2 {
|
||||
font-weight:200;
|
||||
font-size: 28px;
|
||||
float:left;
|
||||
margin: 0px 150px 0px 0px;
|
||||
}
|
||||
.band-setup-genres {
|
||||
width:100%;
|
||||
height:90px;
|
||||
background-color:#c5c5c5;
|
||||
border:none;
|
||||
-webkit-box-shadow: inset 2px 2px 3px 0px #888;
|
||||
box-shadow: inset 2px 2px 3px 0px #888;
|
||||
color:#000;
|
||||
overflow:auto;
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
.band-profile-status {
|
||||
font-size:12px;
|
||||
float:left;
|
||||
display:inline-block;
|
||||
vertical-align:middle;
|
||||
line-height:30px;
|
||||
}
|
||||
.band-setup-photo {
|
||||
|
||||
.band-profile-photo {
|
||||
height: 95px;
|
||||
width: 15%;
|
||||
float:left;
|
||||
}
|
||||
.avatar-space {
|
||||
color: $color2;
|
||||
margin: 20px;
|
||||
position:relative;
|
||||
min-height:300px;
|
||||
|
||||
.band-profile-nav {
|
||||
width:85%;
|
||||
position:relative;
|
||||
float:right;
|
||||
margin-right:-10px;
|
||||
}
|
||||
|
||||
.band-profile-nav a {
|
||||
width:24%;
|
||||
text-align:center;
|
||||
height: 27px;
|
||||
display: block;
|
||||
float:left;
|
||||
margin-right:5px;
|
||||
vertical-align:bottom;
|
||||
padding-top:65px;
|
||||
background-color:#535353;
|
||||
color:#ccc;
|
||||
font-size:17px;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
.band-profile-nav a:hover {
|
||||
background-color:#666;
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
.band-profile-nav a.active {
|
||||
background-color:#ed3618;
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
.band-profile-nav a.active:hover {
|
||||
background-color:#ed3618;
|
||||
cursor:default;
|
||||
}
|
||||
|
||||
.band-profile-nav a.last {
|
||||
margin-right:0px !important;
|
||||
}
|
||||
|
||||
.avatar-profile {
|
||||
float:left;
|
||||
padding:2px;
|
||||
width:88px;
|
||||
height:88px;
|
||||
background-color:#ed3618;
|
||||
-webkit-border-radius:44px;
|
||||
-moz-border-radius:44px;
|
||||
border-radius:44px;
|
||||
}
|
||||
|
||||
.avatar-profile img {
|
||||
width:88px;
|
||||
height:88px;
|
||||
-webkit-border-radius:44px;
|
||||
-moz-border-radius:44px;
|
||||
border-radius:44px;
|
||||
}
|
||||
|
||||
.band-profile-wrapper {
|
||||
padding:10px 25px 10px 25px;
|
||||
font-size:15px;
|
||||
color:#ccc;
|
||||
border-bottom: dotted 1px #444;
|
||||
position:relative;
|
||||
display:block;
|
||||
|
||||
.result-name {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 2px;
|
||||
padding-right:4px;
|
||||
}
|
||||
.stats {
|
||||
margin-top: 4px;
|
||||
img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
.lcol {
|
||||
width: 200px;
|
||||
}
|
||||
.whitespace {
|
||||
// equal to lcol width.
|
||||
padding-left: 200px;
|
||||
}
|
||||
.instruments {
|
||||
width:128px;
|
||||
img {
|
||||
height:24px;
|
||||
width:24px;
|
||||
margin-right:2px;
|
||||
|
||||
&:last-child {
|
||||
margin-right:0px;
|
||||
img.preview_profile_avatar {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.spinner-large {
|
||||
width:300px;
|
||||
height:300px;
|
||||
line-height: 300px;
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
z-index: 2000; // to win over jcrop
|
||||
}
|
||||
|
||||
.no-avatar-space {
|
||||
border:1px dotted $color2;
|
||||
|
||||
color: $color2;
|
||||
width:300px;
|
||||
height:300px;
|
||||
line-height: 300px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
background-color:$ColorTextBoxBackground;
|
||||
|
||||
}
|
||||
}
|
||||
.button-row {
|
||||
margin-top:10px;
|
||||
margin-bottom:5px;
|
||||
.result-list-button-wrapper {
|
||||
margin:0;
|
||||
|
||||
.band-profile-header {
|
||||
padding:20px;
|
||||
height:120px;
|
||||
}
|
||||
|
||||
.band-profile-header h2 {
|
||||
font-weight:200;
|
||||
font-size: 28px;
|
||||
float:left;
|
||||
margin: 0px 150px 0px 0px;
|
||||
}
|
||||
|
||||
.band-profile-status {
|
||||
font-size:12px;
|
||||
float:left;
|
||||
display:inline-block;
|
||||
vertical-align:middle;
|
||||
line-height:30px;
|
||||
}
|
||||
|
||||
.band-profile-photo {
|
||||
height: 95px;
|
||||
width: 15%;
|
||||
float:left;
|
||||
}
|
||||
|
||||
.band-profile-nav {
|
||||
width:85%;
|
||||
position:relative;
|
||||
float:right;
|
||||
margin-right:-10px;
|
||||
}
|
||||
|
||||
.band-profile-nav a {
|
||||
width:24%;
|
||||
text-align:center;
|
||||
height: 27px;
|
||||
display: block;
|
||||
float:left;
|
||||
margin-right:5px;
|
||||
vertical-align:bottom;
|
||||
padding-top:65px;
|
||||
background-color:#535353;
|
||||
color:#ccc;
|
||||
font-size:17px;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
.band-profile-nav a:hover {
|
||||
background-color:#666;
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
.band-profile-nav a.active {
|
||||
background-color:#ed3618;
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
.band-profile-nav a.active:hover {
|
||||
background-color:#ed3618;
|
||||
cursor:default;
|
||||
}
|
||||
|
||||
.band-profile-nav a.last {
|
||||
margin-right:0px !important;
|
||||
}
|
||||
|
||||
.band-avatar-profile {
|
||||
padding:2px;
|
||||
width:88px;
|
||||
height:88px;
|
||||
background-color:#ed3618;
|
||||
-webkit-border-radius:44px;
|
||||
-moz-border-radius:44px;
|
||||
border-radius:44px;
|
||||
}
|
||||
|
||||
.band-avatar-profile img {
|
||||
width:88px;
|
||||
height:88px;
|
||||
-webkit-border-radius:44px;
|
||||
-moz-border-radius:44px;
|
||||
border-radius:44px;
|
||||
}
|
||||
|
||||
// .band-name, .band-photo {
|
||||
// display: inline;
|
||||
// }
|
||||
|
||||
.band-profile-wrapper {
|
||||
padding:10px 25px 10px 25px;
|
||||
font-size:15px;
|
||||
color:#ccc;
|
||||
border-bottom: dotted 1px #444;
|
||||
position:relative;
|
||||
display:block;
|
||||
|
||||
.result-name {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 2px;
|
||||
padding-right:4px;
|
||||
}
|
||||
.stats {
|
||||
margin-top: 4px;
|
||||
img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
.lcol {
|
||||
width: 200px;
|
||||
}
|
||||
.whitespace {
|
||||
// equal to lcol width.
|
||||
padding-left: 200px;
|
||||
}
|
||||
.instruments {
|
||||
width:128px;
|
||||
img {
|
||||
height:24px;
|
||||
width:24px;
|
||||
margin-right:2px;
|
||||
|
||||
&:last-child {
|
||||
margin-right:0px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.button-row {
|
||||
margin-top:10px;
|
||||
margin-bottom:5px;
|
||||
.result-list-button-wrapper {
|
||||
margin:0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.band-profile-about-left {
|
||||
width:16%;
|
||||
float:left;
|
||||
font-size:13px;
|
||||
line-height:140%;
|
||||
display:block;
|
||||
}
|
||||
|
||||
.band-profile-about-left h3 {
|
||||
color:#fff;
|
||||
margin-bottom:0px;
|
||||
font-size:13px;
|
||||
font-weight:bold;
|
||||
display:inline;
|
||||
}
|
||||
|
||||
.band-profile-about-right {
|
||||
float:right;
|
||||
font-size:13px;
|
||||
width:84%;
|
||||
line-height:140%;
|
||||
display:block;
|
||||
}
|
||||
|
||||
.band-profile-about-right .band-profile-instrument {
|
||||
text-align:center;
|
||||
margin-right:15px;
|
||||
float:left;
|
||||
}
|
||||
|
||||
.proficiency-beginner {
|
||||
font-size:10px;
|
||||
color:#8ea415;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
.proficiency-intermediate {
|
||||
font-size:10px;
|
||||
color:#0b6672;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
.proficiency-expert {
|
||||
font-size:10px;
|
||||
color:#ed3618;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
.band-profile-members {
|
||||
width:100%;
|
||||
min-height:90px;
|
||||
background-color:#242323;
|
||||
position:relative;
|
||||
float:left;
|
||||
margin:10px 20px 10px 0px;
|
||||
padding-bottom:5px;
|
||||
}
|
||||
|
||||
.band-profile-member-name {
|
||||
float:left;
|
||||
font-size:12px;
|
||||
margin-top:12px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.band-profile-member-location {
|
||||
font-size:12px;
|
||||
font-weight:200;
|
||||
}
|
||||
|
||||
.band-profile-member-genres {
|
||||
float:left;
|
||||
width:40%;
|
||||
font-size:10px;
|
||||
margin-left:10px;
|
||||
padding-right:5px;
|
||||
}
|
||||
|
||||
.band-profile-social-left {
|
||||
float:left;
|
||||
width:32%;
|
||||
margin-right:12px;
|
||||
border-right:solid 1px #666;
|
||||
}
|
||||
|
||||
.band-profile-social-mid {
|
||||
float:left;
|
||||
width:31%;
|
||||
margin-right:12px;
|
||||
border-right:solid 1px #666;
|
||||
}
|
||||
|
||||
.band-profile-social-right {
|
||||
float:left;
|
||||
width:31%;
|
||||
}
|
||||
|
||||
.band-profile-social-left h2, .band-profile-social-mid h2, .band-profile-social-right h2 {
|
||||
font-weight:200;
|
||||
color:#fff;
|
||||
font-size:20px;
|
||||
}
|
||||
|
||||
.band-profile-block {
|
||||
clear:left;
|
||||
white-space:nowrap;
|
||||
display:block;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
.band-profile-outer-block {
|
||||
float: left;
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.band-profile-block-name {
|
||||
display:inline-block;
|
||||
margin-top:13px;
|
||||
font-size:14px;
|
||||
color:#fff;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.band-profile-block-city {
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
#band-filter-results {
|
||||
margin: 0 10px 5px 10px;
|
||||
}
|
||||
|
||||
.band-list-result {
|
||||
padding-top: 5px;
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.band-wrapper {
|
||||
overflow: auto;
|
||||
height: 480px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#band-setup-form {
|
||||
padding: 0.25em 0.5em 0.25em 0.25em;
|
||||
#band-setup-table {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.band-profile-about-left {
|
||||
width:16%;
|
||||
float:left;
|
||||
font-size:13px;
|
||||
line-height:140%;
|
||||
display:block;
|
||||
}
|
||||
.easydropdown {
|
||||
padding: 0 3px;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.band-profile-about-left h3 {
|
||||
color:#fff;
|
||||
margin-bottom:0px;
|
||||
font-size:13px;
|
||||
font-weight:bold;
|
||||
display:inline;
|
||||
}
|
||||
.easydropdown-wrapper {
|
||||
width:80%;
|
||||
}
|
||||
|
||||
.band-profile-about-right {
|
||||
float:right;
|
||||
font-size:13px;
|
||||
width:84%;
|
||||
line-height:140%;
|
||||
display:block;
|
||||
}
|
||||
div.field {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.band-profile-about-right .band-profile-instrument {
|
||||
text-align:center;
|
||||
margin-right:15px;
|
||||
float:left;
|
||||
}
|
||||
|
||||
.proficiency-beginner {
|
||||
font-size:10px;
|
||||
color:#8ea415;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
.proficiency-intermediate {
|
||||
font-size:10px;
|
||||
color:#0b6672;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
.proficiency-expert {
|
||||
font-size:10px;
|
||||
color:#ed3618;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
.band-profile-members {
|
||||
width:100%;
|
||||
min-height:90px;
|
||||
background-color:#242323;
|
||||
position:relative;
|
||||
float:left;
|
||||
margin:10px 20px 10px 0px;
|
||||
padding-bottom:5px;
|
||||
}
|
||||
|
||||
.band-profile-member-name {
|
||||
float:left;
|
||||
font-size:12px;
|
||||
margin-top:12px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.band-profile-member-location {
|
||||
font-size:12px;
|
||||
font-weight:200;
|
||||
}
|
||||
|
||||
.band-profile-member-genres {
|
||||
float:left;
|
||||
width:40%;
|
||||
font-size:10px;
|
||||
margin-left:10px;
|
||||
padding-right:5px;
|
||||
}
|
||||
|
||||
.band-profile-social-left {
|
||||
float:left;
|
||||
width:32%;
|
||||
margin-right:12px;
|
||||
border-right:solid 1px #666;
|
||||
}
|
||||
|
||||
.band-profile-social-mid {
|
||||
float:left;
|
||||
width:31%;
|
||||
margin-right:12px;
|
||||
border-right:solid 1px #666;
|
||||
}
|
||||
|
||||
.band-profile-social-right {
|
||||
float:left;
|
||||
width:31%;
|
||||
}
|
||||
|
||||
.band-profile-social-left h2, .band-profile-social-mid h2, .band-profile-social-right h2 {
|
||||
font-weight:200;
|
||||
color:#fff;
|
||||
font-size:20px;
|
||||
}
|
||||
|
||||
.band-profile-block {
|
||||
clear:left;
|
||||
white-space:nowrap;
|
||||
display:block;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
.band-profile-outer-block {
|
||||
float: left;
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.band-profile-block-name {
|
||||
display:inline-block;
|
||||
margin-top:13px;
|
||||
font-size:14px;
|
||||
color:#fff;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.band-profile-block-city {
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
#band-filter-results {
|
||||
margin: 0 10px 5px 10px;
|
||||
}
|
||||
|
||||
.band-list-result {
|
||||
padding-top: 5px;
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.band-wrapper {
|
||||
overflow: auto;
|
||||
height: 480px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#band-setup-form {
|
||||
.easydropdown {
|
||||
padding: 0 3px;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.easydropdown-wrapper {
|
||||
width:80%;
|
||||
}
|
||||
|
||||
div.field {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
label {
|
||||
margin-bottom:2px;
|
||||
label {
|
||||
margin-bottom:2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@
|
|||
*= require ./checkout_payment
|
||||
*= require ./checkout_order
|
||||
*= require ./checkout_complete
|
||||
*= require ./redeem_signup
|
||||
*= require ./redeem_complete
|
||||
*= require ./genreSelector
|
||||
*= require ./sessionList
|
||||
*= require ./searchResults
|
||||
|
|
@ -78,4 +80,5 @@
|
|||
*= require users/syncViewer
|
||||
*= require ./downloadJamTrack
|
||||
*= require ./jamTrackPreview
|
||||
*= require users/signinCommon
|
||||
*/
|
||||
|
|
@ -314,30 +314,6 @@ a.gold {
|
|||
color: #cc9900 !important;
|
||||
}
|
||||
|
||||
a.arrow-up {
|
||||
float:right;
|
||||
margin-right:5px;
|
||||
display:block;
|
||||
margin-top:6px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 7px solid transparent;
|
||||
border-right: 7px solid transparent;
|
||||
border-bottom: 7px solid #333;
|
||||
}
|
||||
|
||||
a.arrow-down {
|
||||
float:right;
|
||||
margin-right:5px;
|
||||
display:block;
|
||||
margin-top:6px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 7px solid transparent;
|
||||
border-right: 7px solid transparent;
|
||||
border-top: 7px solid #333;
|
||||
}
|
||||
|
||||
.settings-session-description {
|
||||
padding:10px;
|
||||
width:200px;
|
||||
|
|
@ -537,6 +513,32 @@ ul.shortcuts {
|
|||
padding:2px 8px !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
a.arrow-up {
|
||||
float:right;
|
||||
margin-right:5px;
|
||||
display:block;
|
||||
margin-top:6px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 7px solid transparent;
|
||||
border-right: 7px solid transparent;
|
||||
border-bottom: 7px solid #333;
|
||||
}
|
||||
|
||||
a.arrow-down {
|
||||
float:right;
|
||||
margin-right:5px;
|
||||
display:block;
|
||||
margin-top:6px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 7px solid transparent;
|
||||
border-right: 7px solid transparent;
|
||||
border-top: 7px solid #333;
|
||||
}
|
||||
|
||||
a.arrow-up-orange {
|
||||
margin-left:5px;
|
||||
margin-bottom:2px;
|
||||
|
|
|
|||
|
|
@ -68,4 +68,10 @@
|
|||
display:none;
|
||||
}
|
||||
}
|
||||
|
||||
.adds-line-break {
|
||||
display:block;
|
||||
margin-left:66px;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
table.jamtrack-table {
|
||||
table-layout:fixed;
|
||||
}
|
||||
.jamtrack-content {
|
||||
text-align: center;
|
||||
border: 1px solid #222222;
|
||||
|
|
@ -47,22 +50,41 @@
|
|||
text-align: left;
|
||||
}
|
||||
|
||||
th.jamtrack-detail {
|
||||
padding:6px;
|
||||
}
|
||||
|
||||
th.jamtrack-tracks {
|
||||
padding:6px;
|
||||
}
|
||||
|
||||
th.jamtrack-action {
|
||||
padding:6px;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
td.jamtrack-action {
|
||||
padding:0;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.jamtrack-detail {
|
||||
@include border_box_sizing;
|
||||
width: 35%;
|
||||
width: 25%;
|
||||
padding: 10px 0 0 10px;
|
||||
.detail-label {
|
||||
width: 40%;
|
||||
width: 80px;
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
font-weight: 400;
|
||||
font-size: 11px;
|
||||
clear:both;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
width: 50%;
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
margin-bottom:15px;
|
||||
font-size:11px;
|
||||
}
|
||||
|
||||
|
|
@ -84,12 +106,37 @@
|
|||
margin-right: 5px;
|
||||
padding-top: 5px;
|
||||
vertical-align: bottom;
|
||||
color:#fc0;
|
||||
|
||||
.arrow-down {
|
||||
float:none;
|
||||
margin-left:5px;
|
||||
margin-top:0;
|
||||
margin-right:0;
|
||||
border-top: 4px solid #fc0;
|
||||
border-left: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
display:inline-block;
|
||||
}
|
||||
.arrow-up {
|
||||
float:none;
|
||||
margin-right:0;
|
||||
margin-left:5px;
|
||||
margin-bottom:2px;
|
||||
border-bottom: 4px solid #fc0;
|
||||
border-left: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
display:inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.jamtrack-tracks {
|
||||
padding-bottom:30px;
|
||||
position:relative;
|
||||
@include border_box_sizing;
|
||||
width: 45%;
|
||||
padding: 10px 0px;
|
||||
width:55%;
|
||||
//padding: 10px 0px;
|
||||
|
||||
.tracks-caption {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
|
|
@ -117,12 +164,31 @@
|
|||
|
||||
|
||||
.detail-arrow {
|
||||
position:absolute;
|
||||
float: right;
|
||||
margin-right: 10px;
|
||||
bottom:14px;
|
||||
left:12px;
|
||||
}
|
||||
|
||||
.jamtrack-name {
|
||||
font-size:16px;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.jamtrack-original-artist {
|
||||
font-size:16px;
|
||||
margin-top:10px;
|
||||
margin-bottom:5px;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
|
||||
.jamtrack-track {
|
||||
margin:0 0 8px 7px;
|
||||
float:left;
|
||||
padding:0 0 8px 7px;
|
||||
width: 250px;
|
||||
@include border_box_sizing;
|
||||
|
||||
&.hidden {
|
||||
display:none;
|
||||
|
|
@ -131,14 +197,23 @@
|
|||
|
||||
.jam-track-preview {
|
||||
font-size:11px;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
.jamtrack-action {
|
||||
@include border_box_sizing;
|
||||
width: 20%;
|
||||
// padding: 0px 0px;
|
||||
text-align: center;
|
||||
// vertical-align: top;
|
||||
|
||||
.jamtrack-action-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position:absolute;
|
||||
height:100%;
|
||||
width:100%;
|
||||
|
||||
}
|
||||
.play-button {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
|
@ -149,6 +224,7 @@
|
|||
|
||||
&.free {
|
||||
margin-top:0;
|
||||
display:none;
|
||||
.free-state {
|
||||
font-size: 11px;
|
||||
margin-top: 5px;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
@import "client/common.css.scss";
|
||||
#redeemCompleteScreen {
|
||||
|
||||
p {
|
||||
font-size:14px;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.order-prompt {
|
||||
color:white;
|
||||
line-height:125%;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color:white;
|
||||
font-weight:normal;
|
||||
margin: 0 0 10px 0;
|
||||
font-size:14px;
|
||||
padding: 3px 0 3px 10px;
|
||||
height: 14px;
|
||||
line-height: 14px;
|
||||
vertical-align: middle;
|
||||
text-align:left;
|
||||
|
||||
&.purchased-jam-track-header {
|
||||
background-color:#4d4d4d;
|
||||
}
|
||||
}
|
||||
|
||||
.action-bar {
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
#checkout-info-help {
|
||||
margin-right:1px;
|
||||
}
|
||||
|
||||
.checkout-complete-wrapper {
|
||||
padding:50px;
|
||||
}
|
||||
|
||||
.why-download {
|
||||
margin-top:20px;
|
||||
}
|
||||
|
||||
.no-purchases-prompt {
|
||||
|
||||
}
|
||||
|
||||
.jam-tracks-in-browser {
|
||||
|
||||
}
|
||||
.thanks-panel {
|
||||
|
||||
|
||||
span.notice {
|
||||
font-style:italic;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
br.purchase-downloads {
|
||||
clear:both;
|
||||
margin-bottom:20px;
|
||||
}
|
||||
|
||||
.download-jamkazam {
|
||||
color:$ColorLink;
|
||||
border-radius: 4px;
|
||||
border-style:solid;
|
||||
border-color:#AAA;
|
||||
border-width:1px;
|
||||
padding:10px;
|
||||
margin-top:20px;
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
.download-jamkazam-wrapper {
|
||||
text-align:center;
|
||||
display:block;
|
||||
margin-top:35px;
|
||||
|
||||
&.hidden {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
.thanks-detail.purchased-jam-track {
|
||||
|
||||
margin-top:20px;
|
||||
|
||||
.purchased-jam-track-header {
|
||||
font-size: 15px;
|
||||
margin-bottom:10px;
|
||||
|
||||
span {
|
||||
display:none;
|
||||
}
|
||||
|
||||
&[status="in-progress"] {
|
||||
span.in-progress-msg {
|
||||
display:inline;
|
||||
}
|
||||
}
|
||||
|
||||
&[status="done"] {
|
||||
span.done-msg {
|
||||
display:inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul.purchased-list {
|
||||
float:left;
|
||||
margin:20px 100px 0 20px;
|
||||
|
||||
li {
|
||||
margin:0;
|
||||
}
|
||||
}
|
||||
|
||||
.download-jamtrack {
|
||||
width:auto;
|
||||
vertical-align: middle; // to make bullets mid-align when error shows
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,247 @@
|
|||
@import "client/common.css.scss";
|
||||
|
||||
#redeemSignupScreen {
|
||||
|
||||
.redeem-signup {
|
||||
padding:30px;
|
||||
}
|
||||
.g-recaptcha {
|
||||
//transform:scale(0.80);
|
||||
//transform-origin:0 0;
|
||||
}
|
||||
|
||||
.jamtrack-name {
|
||||
font-weight:bold;
|
||||
}
|
||||
.content-holder {
|
||||
|
||||
//margin-top:40px;
|
||||
color:$ColorTextTypical;
|
||||
|
||||
&.signed-in {
|
||||
.left-side, .right-side {
|
||||
display:none;
|
||||
}
|
||||
.not-signed-in.prompt {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
&.not-signed-in {
|
||||
.already-signed-in {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.not-signed-in.prompt {
|
||||
text-align:center;
|
||||
}
|
||||
.already-signed-in {
|
||||
text-align:center;
|
||||
h3 {
|
||||
text-align:center;
|
||||
}
|
||||
}
|
||||
|
||||
a.forgot-password {
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
font-size:10px;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
margin:0;
|
||||
|
||||
li {
|
||||
margin-bottom:5px;
|
||||
}
|
||||
}
|
||||
|
||||
.signup-submit {
|
||||
margin-right:2px;
|
||||
}
|
||||
|
||||
.signup-facebook {
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.signup-later-prompt {
|
||||
margin:30px 0 30px 0;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.signup-prompt {
|
||||
float:right;
|
||||
text-align:left;
|
||||
margin:30px 0 15px 0;
|
||||
width:60%;
|
||||
max-width:300px;
|
||||
@include border_box_sizing;
|
||||
|
||||
span {
|
||||
text-align:left;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
font-size:14px;
|
||||
line-height:125%;
|
||||
}
|
||||
|
||||
|
||||
.login-error {
|
||||
|
||||
div.actions {
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
.field {
|
||||
background-color: #330000;
|
||||
border: 1px solid #990000;
|
||||
padding:8px;
|
||||
}
|
||||
}
|
||||
|
||||
.field {
|
||||
display:block;
|
||||
@include border_box_sizing;
|
||||
padding:6px 8px;
|
||||
margin:0px -8px;
|
||||
white-space: nowrap;
|
||||
|
||||
&.error {
|
||||
background-color:#300;
|
||||
border: solid 1px #900;
|
||||
|
||||
li {
|
||||
list-style:none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login-error-msg {
|
||||
display:none;
|
||||
margin-top:10px;
|
||||
text-align:center;
|
||||
color:#F00;
|
||||
font-size:11px;
|
||||
width:60%;
|
||||
max-width:300px;
|
||||
@include border_box_sizing;
|
||||
float:right;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
|
||||
.login-error .login-error-msg {
|
||||
display:block;
|
||||
}
|
||||
|
||||
h3
|
||||
{
|
||||
color:$ColorTextHighlight;
|
||||
text-align:left;
|
||||
font-size:16px;
|
||||
font-weight:700;
|
||||
margin-bottom:15px;
|
||||
}
|
||||
|
||||
input {
|
||||
@include border_box_sizing;
|
||||
}
|
||||
|
||||
|
||||
.btnNext {
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.left-side, .right-side {
|
||||
margin-top:50px;
|
||||
}
|
||||
.left-side {
|
||||
float:left;
|
||||
width:50%;
|
||||
@include border_box_sizing;
|
||||
border-width:0 1px 0 0;
|
||||
border-color:white;
|
||||
border-style:solid;
|
||||
text-align:right;
|
||||
padding: 0 60px;
|
||||
margin-bottom:20px;
|
||||
|
||||
.actions {
|
||||
width:60%;
|
||||
max-width:300px;
|
||||
@include border_box_sizing;
|
||||
position:relative;
|
||||
float:right;
|
||||
}
|
||||
|
||||
.terms_of_service {
|
||||
text-align:center;
|
||||
label {
|
||||
display:inline;
|
||||
}
|
||||
font-size:11px;
|
||||
}
|
||||
}
|
||||
|
||||
a.signin {
|
||||
text-decoration: underline;
|
||||
font-size:12px;
|
||||
margin-left:15px;
|
||||
}
|
||||
.left-side-content {
|
||||
@include border_box_sizing;
|
||||
float:right;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
|
||||
.right-side {
|
||||
float:left;
|
||||
width:50%;
|
||||
@include border_box_sizing;
|
||||
padding: 0 60px;
|
||||
|
||||
.actions {
|
||||
margin-top:11px;
|
||||
margin-left:-8px;
|
||||
white-space: nowrap;
|
||||
input {
|
||||
width:auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
input {
|
||||
width:80%;
|
||||
max-width:300px;
|
||||
}
|
||||
label {
|
||||
display:inline-block;
|
||||
width:80px;
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
.terms_of_service {
|
||||
input {
|
||||
width: auto;
|
||||
margin-left: -2px;
|
||||
}
|
||||
label {
|
||||
display:inline;
|
||||
}
|
||||
font-size:11px;
|
||||
}
|
||||
}
|
||||
|
||||
.facebook-prompt {
|
||||
margin:40px 0 10px 0;
|
||||
float:right;
|
||||
text-align:left;
|
||||
width:249px;
|
||||
@include border_box_sizing;
|
||||
}
|
||||
}
|
||||
|
|
@ -16,17 +16,20 @@ body.web.landing_jamtrack.individual_jamtrack {
|
|||
width:90%;
|
||||
}
|
||||
|
||||
.prompt {
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
.jam-track-preview-holder {
|
||||
|
||||
margin-bottom: 7px;
|
||||
float: left;
|
||||
|
||||
&[data-track-type="Master"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&[data-track-type="Track"] {
|
||||
width: 50%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,17 +16,20 @@ body.web.landing_jamtrack.individual_jamtrack_band {
|
|||
width:90%;
|
||||
}
|
||||
|
||||
.prompt {
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
.jam-track-preview-holder {
|
||||
|
||||
margin-bottom: 7px;
|
||||
float: left;
|
||||
|
||||
&[data-track-type="Master"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&[data-track-type="Track"] {
|
||||
width: 50%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,28 @@
|
|||
|
||||
body.web.landing_page {
|
||||
|
||||
div.cta-free-jamtrack {
|
||||
top: 32px;
|
||||
position: absolute;
|
||||
left: 383px;
|
||||
|
||||
a {
|
||||
width: 296px;
|
||||
height: 57px;
|
||||
}
|
||||
|
||||
.value-indicator {
|
||||
position:absolute;
|
||||
left: 311px;
|
||||
top: 19px;
|
||||
width:80px;
|
||||
}
|
||||
|
||||
img {
|
||||
height:100%;
|
||||
width:100%;
|
||||
}
|
||||
}
|
||||
.two_by_two {
|
||||
|
||||
h1 {
|
||||
|
|
@ -29,6 +51,41 @@ body.web.landing_page {
|
|||
}
|
||||
}
|
||||
|
||||
.one_by_two {
|
||||
h1 {
|
||||
margin:0 0 5px;
|
||||
padding:7px 0;
|
||||
display:inline-block;
|
||||
|
||||
&.hidden {
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
.row {
|
||||
@include border_box_sizing;
|
||||
|
||||
&:nth-of-type(1) {
|
||||
padding:20px 0 0 0;
|
||||
}
|
||||
|
||||
.column {
|
||||
@include border_box_sizing;
|
||||
|
||||
&:nth-of-type(1) {
|
||||
width:35%;
|
||||
}
|
||||
|
||||
&:nth-of-type(2) {
|
||||
width:65%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.video-container {
|
||||
width:100%;
|
||||
padding-bottom:56.25%;
|
||||
}
|
||||
}
|
||||
|
||||
&.landing_jamtrack, &.landing_product {
|
||||
|
||||
.landing-tag {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@
|
|||
height:auto;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
label {
|
||||
margin-bottom:2px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,13 +73,25 @@ class ApiJamTracksController < ApiController
|
|||
|
||||
def download
|
||||
if @jam_track_right.valid?
|
||||
|
||||
all_fingerprint = params[:all_fp]
|
||||
running_fingerprint = params[:running_fp]
|
||||
|
||||
if Rails.application.config.guard_against_fraud
|
||||
error = @jam_track_right.guard_against_fraud(current_user, {all:all_fingerprint, running: running_fingerprint}, request.remote_ip)
|
||||
if error
|
||||
log.warn("potential fraud detected: #{error}")
|
||||
render :json => { :message => error }, :status => 403
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
sample_rate = params[:sample_rate].nil? ? nil : params[:sample_rate].to_i
|
||||
if @jam_track_right && @jam_track_right.ready?(sample_rate)
|
||||
@jam_track_right.update_download_count
|
||||
@jam_track_right.last_downloaded_at = Time.now
|
||||
if @jam_track_right.first_downloaded_at.nil?
|
||||
@jam_track_right.first_downloaded_at = Time.now
|
||||
end
|
||||
now = Time.now
|
||||
@jam_track_right.last_downloaded_at = now
|
||||
@jam_track_right.first_downloaded_at = now if @jam_track_right.first_downloaded_at.nil?
|
||||
@jam_track_right.save!
|
||||
redirect_to @jam_track_right.sign_url(120, sample_rate)
|
||||
else
|
||||
|
|
@ -92,6 +104,18 @@ class ApiJamTracksController < ApiController
|
|||
end
|
||||
|
||||
def enqueue
|
||||
|
||||
fingerprint = params[:fingerprint]
|
||||
|
||||
if Rails.application.config.guard_against_fraud
|
||||
error = @jam_track_right.guard_against_fraud(current_user, fingerprint, request.remote_ip)
|
||||
if error
|
||||
log.warn("potential fraud detected: #{error}")
|
||||
render :json => { :message => error }, :status => 403
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
sample_rate = params[:sample_rate].nil? ? nil : params[:sample_rate].to_i
|
||||
enqueued = @jam_track_right.enqueue_if_needed(sample_rate)
|
||||
log.debug("jamtrack #{enqueued ? "ENQUEUED" : "NOT ENQUEUED"}: jam_track_right=#{@jam_track_right.id} sample_rate=#{sample_rate} ")
|
||||
|
|
@ -119,7 +143,7 @@ class ApiJamTracksController < ApiController
|
|||
|
||||
|
||||
# jamtracks come in the form id-44 or id-48, so we need to do a little extra parsing
|
||||
puts "#{jamtracks.inspect}"
|
||||
|
||||
jamtrack_ids = Set.new
|
||||
jamtracks_fq_ids = Set.new
|
||||
jamtracks.each do |jamtrack|
|
||||
|
|
@ -131,8 +155,6 @@ class ApiJamTracksController < ApiController
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
puts "#{jamtrack_ids.inspect} #{jamtracks_fq_ids.inspect}"
|
||||
@jam_tracks = JamTrackRight.list_keys(current_user, jamtrack_ids)
|
||||
@jamtracks_fq_ids = jamtracks_fq_ids
|
||||
end
|
||||
|
|
|
|||
|
|
@ -25,26 +25,20 @@ class ApiRecurlyController < ApiController
|
|||
# keep reuse card up-to-date
|
||||
User.where(id: current_user.id).update_all(reuse_card: params[:reuse_card_next_time])
|
||||
else
|
||||
|
||||
options = {
|
||||
remote_ip: request.remote_ip,
|
||||
first_name: billing_info[:first_name],
|
||||
last_name: billing_info[:last_name],
|
||||
email: params[:email],
|
||||
password: params[:password],
|
||||
password_confirmation: params[:password],
|
||||
terms_of_service: terms_of_service,
|
||||
instruments: [{:instrument_id => 'other', :proficiency_level => 1, :priority => 1}],
|
||||
birth_date: nil,
|
||||
location: {:country => billing_info[:country], :state => billing_info[:state], :city => billing_info[:city]},
|
||||
musician: true,
|
||||
skip_recaptcha: true,
|
||||
invited_user: nil,
|
||||
fb_signup: nil,
|
||||
signup_confirm_url: ApplicationHelper.base_uri(request) + "/confirm",
|
||||
any_user: any_user,
|
||||
reuse_card: reuse_card_next_time
|
||||
}
|
||||
|
||||
options = User.musician_defaults(request.remote_ip, ApplicationHelper.base_uri(request) + "/confirm", any_user, options)
|
||||
|
||||
user = UserManager.new.signup(options)
|
||||
|
||||
if user.errors.any?
|
||||
|
|
@ -142,6 +136,7 @@ class ApiRecurlyController < ApiController
|
|||
if error
|
||||
render json: {errors: {message: error}}, :status => 404
|
||||
else
|
||||
set_purchased_jamtrack_cookie
|
||||
render :json => response, :status => 200
|
||||
end
|
||||
rescue RecurlyClientError => x
|
||||
|
|
|
|||
|
|
@ -51,6 +51,15 @@ class ApiShoppingCartsController < ApiController
|
|||
respond_with responder: ApiResponder, :status => 204
|
||||
end
|
||||
|
||||
# take all shopping carts from anonymous user and copy them to logged in user
|
||||
def port
|
||||
if current_user && anonymous_user
|
||||
ShoppingCart.port(current_user, anonymous_user)
|
||||
else
|
||||
render :json => {message: 'one or both users not available'}, :status => 403
|
||||
end
|
||||
end
|
||||
|
||||
def clear_all
|
||||
any_user.destroy_all_shopping_carts
|
||||
render :json=>{}, :status=>200
|
||||
|
|
|
|||
|
|
@ -43,9 +43,46 @@ class ApiUsersController < ApiController
|
|||
respond_with @profile, responder: ApiResponder, :status => 200
|
||||
end
|
||||
|
||||
# in other words, a minimal signup
|
||||
def create
|
||||
# today, this only accepts a minimal registration; it could be made to take in more if we wanted
|
||||
signup_hint = nil
|
||||
if anonymous_user
|
||||
signup_hint = anonymous_user.signup_hint
|
||||
if signup_hint && signup_hint.jam_track.nil?
|
||||
signup_hint = nil # it doesn't make sense to pass in signup hints that are not free jam-track centric (at least, not today)
|
||||
end
|
||||
end
|
||||
|
||||
# recaptcha_response: params['g-recaptcha-response']
|
||||
|
||||
options = {
|
||||
first_name: params[:first_name],
|
||||
last_name: params[:last_name],
|
||||
email: params[:email],
|
||||
password: params[:password],
|
||||
password_confirmation: params[:password],
|
||||
terms_of_service: params[:terms],
|
||||
location: {:country => nil, :state => nil, :city => nil},
|
||||
signup_hint: signup_hint
|
||||
}
|
||||
|
||||
options = User.musician_defaults(request.remote_ip, ApplicationHelper.base_uri(request) + "/confirm", any_user, options)
|
||||
|
||||
@user = UserManager.new.signup(options)
|
||||
|
||||
if @user.errors.any?
|
||||
respond_with_model(@user)
|
||||
else
|
||||
sign_in @user
|
||||
new_user(@user, signup_hint) # sets a cookie used for GA analytics (one-time new user stuff in JavaScript)
|
||||
respond_with_model(@user, new: true, location: lambda { return api_user_detail_url(@user.id) })
|
||||
end
|
||||
end
|
||||
|
||||
def profile_save
|
||||
end
|
||||
|
||||
|
||||
def update
|
||||
|
||||
@user = User.find(params[:id])
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class ApplicationController < ActionController::Base
|
|||
cookies.permanent[:user_uuid] = SecureRandom.uuid unless cookies[:user_uuid]
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def add_user_info_to_bugsnag(notif)
|
||||
# Add some app-specific data which will be displayed on a custom
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ class ClientsController < ApplicationController
|
|||
return
|
||||
end
|
||||
|
||||
@in_client_page = true
|
||||
@minimal_curtain = Rails.application.config.minimal_curtain
|
||||
gon.recurly_tax_estimate_jam_track_plan = Rails.application.config.recurly_tax_estimate_jam_track_plan
|
||||
render :layout => 'client'
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ class LandingsController < ApplicationController
|
|||
end
|
||||
|
||||
def individual_jamtrack
|
||||
@no_landing_tag = true
|
||||
@show_cta_free_jamtrack = true
|
||||
@jam_track = JamTrack.find_by_plan_code("jamtrack-" + params[:plan_code])
|
||||
gon.jam_track_plan_code = params[:plan_code] ? "jamtrack-" + params[:plan_code] : nil
|
||||
gon.generic = params[:generic]
|
||||
|
|
@ -74,6 +76,8 @@ class LandingsController < ApplicationController
|
|||
end
|
||||
|
||||
def individual_jamtrack_band
|
||||
@no_landing_tag = true
|
||||
@show_cta_free_jamtrack = true
|
||||
@jam_track = JamTrack.find_by_plan_code("jamtrack-" + params[:plan_code])
|
||||
gon.jam_track_plan_code = params[:plan_code] ? "jamtrack-" + params[:plan_code] : nil
|
||||
|
||||
|
|
|
|||
|
|
@ -121,8 +121,40 @@ class SessionsController < ApplicationController
|
|||
end
|
||||
fb_signup.save!
|
||||
|
||||
redirect_to "#{signup_path}?facebook_signup=#{fb_signup.lookup_id}"
|
||||
return
|
||||
# see if we can find a SignupHint for a JamTrack; if so, bounce them back to the redeemComplete page to let them know we bought it
|
||||
|
||||
if anonymous_user
|
||||
signup_hint = anonymous_user.signup_hint
|
||||
if signup_hint && signup_hint.redirect_location
|
||||
options = {
|
||||
first_name: first_name,
|
||||
last_name: last_name,
|
||||
email: email,
|
||||
terms_of_service: true,
|
||||
location: {:country => nil, :state => nil, :city => nil},
|
||||
}
|
||||
|
||||
options = User.musician_defaults(request.remote_ip, ApplicationHelper.base_uri(request) + "/confirm", any_user, options)
|
||||
|
||||
user = UserManager.new.signup(options)
|
||||
|
||||
if user.errors.any?
|
||||
redirect_to signup_hint.redirect_location
|
||||
return
|
||||
end
|
||||
|
||||
sign_in(user)
|
||||
new_user(user, signup_hint)
|
||||
redirect_to signup_hint.redirect_location
|
||||
return
|
||||
else
|
||||
redirect_to "#{signup_path}?facebook_signup=#{fb_signup.lookup_id}"
|
||||
return
|
||||
end
|
||||
else
|
||||
redirect_to "#{signup_path}?facebook_signup=#{fb_signup.lookup_id}"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if current_user.nil?
|
||||
|
|
|
|||
|
|
@ -180,23 +180,6 @@ class UsersController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
# given the current user, and any signup hint (can be nil)
|
||||
# handle the final destination of the user
|
||||
def handle_signup_hint(user, signup_hint, default_redirect)
|
||||
redirect_url = default_redirect
|
||||
if signup_hint
|
||||
if signup_hint.want_jamblaster
|
||||
User.where(id: user.id).update_all(want_jamblaster: true)
|
||||
end
|
||||
|
||||
if signup_hint.redirect_location
|
||||
redirect_url = signup_hint.redirect_location
|
||||
end
|
||||
end
|
||||
|
||||
redirect_url
|
||||
end
|
||||
|
||||
def congratulations_fan
|
||||
@no_user_dropdown = true
|
||||
render :layout => "web"
|
||||
|
|
@ -383,12 +366,12 @@ class UsersController < ApplicationController
|
|||
end if params[:id].present? && (service=params[:service]).present?
|
||||
|
||||
service ||= 'facebook'
|
||||
url = CGI::escape('http://www.jamkazam.com')
|
||||
url = CGI::escape('https://www.jamkazam.com')
|
||||
txt = CGI::escape('Check out JamKazam -- Play music together over the Internet as if in the same room')
|
||||
if 'twitter'==service
|
||||
url = "https://twitter.com/intent/tweet?text=#{txt}&url=#{url}"
|
||||
elsif 'facebook'==service
|
||||
url = "http://www.facebook.com/sharer/sharer.php?u=#{url}&t=#{txt}"
|
||||
url = "https://www.facebook.com/sharer/sharer.php?u=#{url}&t=#{txt}"
|
||||
elsif 'google'==service
|
||||
url = "https://plus.google.com/share?url=#{url}"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ module SessionsHelper
|
|||
|
||||
def sign_in(user)
|
||||
set_remember_token(user)
|
||||
set_purchased_jamtrack_cookie unless user.has_redeemable_jamtrack
|
||||
self.current_user = user
|
||||
end
|
||||
|
||||
|
|
@ -21,6 +22,12 @@ module SessionsHelper
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
# should be set whenever a user logs in who has redeemed a free jamtrack, or whenever the user
|
||||
def set_purchased_jamtrack_cookie
|
||||
cookies.permanent[:redeemed_jamtrack] = true
|
||||
end
|
||||
|
||||
def complete_sign_in(user, redirect=true)
|
||||
sign_in user
|
||||
|
||||
|
|
@ -64,7 +71,7 @@ module SessionsHelper
|
|||
|
||||
def anonymous_user
|
||||
if anon_cookie
|
||||
@anonymous_user ||= AnonymousUser.new(anon_cookie)
|
||||
@anonymous_user ||= AnonymousUser.new(anon_cookie, cookies)
|
||||
else
|
||||
nil
|
||||
end
|
||||
|
|
@ -88,9 +95,29 @@ module SessionsHelper
|
|||
redirect_location = signup_hint.redirect_location
|
||||
end
|
||||
|
||||
|
||||
cookies[:new_user] = { musician: user.musician, registrationType: user.user_authorization('facebook') ? 'Facebook' : 'Native', want_jamblaster: want_jamblaster, redirect_location: redirect_location }.to_json
|
||||
end
|
||||
|
||||
|
||||
# given the current user, and any signup hint (can be nil)
|
||||
# handle the final destination of the user
|
||||
def handle_signup_hint(user, signup_hint, default_redirect)
|
||||
redirect_url = default_redirect
|
||||
if signup_hint
|
||||
if signup_hint.want_jamblaster
|
||||
User.where(id: user.id).update_all(want_jamblaster: true)
|
||||
end
|
||||
|
||||
if signup_hint.redirect_location
|
||||
redirect_url = signup_hint.redirect_location
|
||||
end
|
||||
end
|
||||
|
||||
redirect_url
|
||||
end
|
||||
|
||||
|
||||
def current_user?(user)
|
||||
user == current_user
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ end
|
|||
|
||||
# give back more info if the user being fetched is yourself
|
||||
if @user == current_user
|
||||
attributes :email, :original_fpfile, :cropped_fpfile, :crop_selection, :session_settings, :show_whats_next, :show_whats_next_count, :subscribe_email, :auth_twitter, :new_notifications, :sales_count, :reuse_card, :purchased_jamtracks_count, :first_downloaded_client_at
|
||||
attributes :email, :original_fpfile, :cropped_fpfile, :crop_selection, :session_settings, :show_whats_next, :show_whats_next_count, :subscribe_email, :auth_twitter, :new_notifications, :sales_count, :reuse_card, :purchased_jamtracks_count, :first_downloaded_client_at, :created_at
|
||||
|
||||
node :geoiplocation do |user|
|
||||
geoiplocation = current_user.geoiplocation
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<!-- Band Profile -->
|
||||
<div layout="screen" layout-id="bandProfile" layout-arg="id" class="screen secondary">
|
||||
<div layout="screen" layout-id="bandProfile" layout-arg="id" class="screen secondary" id="band-profile">
|
||||
<div class="content-head">
|
||||
<div class="content-icon">
|
||||
<%= image_tag "content/icon_bands.png", :size => "19x19" %>
|
||||
|
|
|
|||
|
|
@ -1,154 +0,0 @@
|
|||
<!-- Profile -->
|
||||
<div layout="screen" layout-id="band/setup" layout-arg="id" class="screen secondary" id="band-setup">
|
||||
<div class="content-head">
|
||||
<div class="content-icon">
|
||||
<%= image_tag "content/icon_bands.png", :size => "19x19" %>
|
||||
</div>
|
||||
|
||||
<h1 id="band-setup-title">set up band</h1>
|
||||
|
||||
<%= render "screen_navigation" %>
|
||||
</div>
|
||||
<div class="content-body">
|
||||
<div class="content-body-scroller">
|
||||
<form id="band-setup-form">
|
||||
<div style="display:block;">
|
||||
<div id="band-setup-step-1" class="content-wrapper" style="padding:10px 35px 10px 35px;">
|
||||
<br />
|
||||
<table width="100%" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td valign="top" colspan="2">
|
||||
<h2><span class="band-setup-text-step1">Step 1: </span>General Information</h2>
|
||||
</td>
|
||||
<td id="tdBandPhoto" valign="middle" rowspan="2" width="33%">
|
||||
<a href="#" class="avatar-profile">
|
||||
<%= image_tag "shared/avatar_generic_band.png", {:id => "band-avatar", :align=>"absmiddle", :height => 88, :width => 88 } %>
|
||||
</a>
|
||||
<br/><br/>
|
||||
<a id="band-change-photo" href="#" class="small ml20">Upload band photo.</a><br clear="all"><br/>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="tdBandName" valign="middle" width="33%">
|
||||
<div class="field">
|
||||
<label for="band-name">Band Name:</label>
|
||||
<input id="band-name" type="text" maxlength="1024" value="" class="w80"><br />
|
||||
</div>
|
||||
</td>
|
||||
<td id="tdBandWebsite" valign="middle" width="33%">
|
||||
<div class="field">
|
||||
<label for="band-website">Web Site:</label>
|
||||
<input id="band-website" type="text" maxlength="4000" value="" class="w80">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="tdBandCountry" valign="middle">
|
||||
<div class="field">
|
||||
<label for="band-country">Country:</label>
|
||||
<select id="band-country" class="w80">
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
<td id="tdBandRegion" valign="middle">
|
||||
<div class="field">
|
||||
<label for="band-region">State/Region:</label>
|
||||
<select id="band-region" class="w80">
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
<td id="tdBandCity" valign="middle">
|
||||
<div class="field">
|
||||
<label for="band-city">City:</label>
|
||||
<select id="band-city" class="w80">
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="tdBandGenres" valign="top">
|
||||
<div class="field">
|
||||
<label for="band-genres">Genres:</label>
|
||||
<div class="band-setup-genres w90">
|
||||
<table id="band-genres" width="100%" cellpadding="10" cellspacing="6"></table>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td id="tdBandBiography" valign="top" colspan="2">
|
||||
<div class="field">
|
||||
<label for="band-biography">Description / Bio:</label>
|
||||
<textarea id="band-biography" class="band-setup-bio w90"></textarea>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br clear="all" />
|
||||
<div class="right">
|
||||
<a id="btn-band-setup-cancel" class="button-grey">CANCEL</a>
|
||||
<a id="btn-band-setup-next" class="button-orange">NEXT</a>
|
||||
</div>
|
||||
<div class="clearall"></div>
|
||||
</div>
|
||||
<div id="band-setup-step-2" class="content-wrapper" style="padding:10px 35px 10px 35px; display:none;">
|
||||
<br/>
|
||||
<h2><span class="band-setup-text-step2">Step 2: </span>Add Band Members</h2><br/>
|
||||
<div id="band-setup-invite-musicians"></div>
|
||||
<br/><br/>
|
||||
If your bandmates are not on JamKazam yet, use any of the options below to invite them to join the service.<br/><br/>
|
||||
<div class="left mr20">
|
||||
<div class="left">
|
||||
<a class="btn-email-invitation">
|
||||
<%= image_tag("content/icon_gmail.png", :size => "24x24", :align => "absmiddle") %>
|
||||
</a>
|
||||
</div>
|
||||
<div class="right mt5 ml5">E-mail</div>
|
||||
</div>
|
||||
|
||||
<div class="left mr20">
|
||||
<div class="left">
|
||||
<a class="btn-facebook-invitation">
|
||||
<%= image_tag("content/icon_facebook.png", :size => "24x24", :align => "absmiddle") %>
|
||||
</a>
|
||||
</div>
|
||||
<div class="right mt5 ml5">Facebook</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="left mr20">
|
||||
<div class="left">
|
||||
<a href="/client#/createSession" title="This feature is not yet available.">
|
||||
<%= image_tag("content/icon_twitter.png", :size => "24x24", :align => "absmiddle") %>
|
||||
</a>
|
||||
</div>
|
||||
<div class="right mt5 ml5">Twitter</div>
|
||||
</div> -->
|
||||
<div class="left left">
|
||||
<div class="left">
|
||||
<a class="btn-gmail-invitation">
|
||||
<%= image_tag("content/icon_google.png", :size => "24x24", :align => "absmiddle") %>
|
||||
</a>
|
||||
</div>
|
||||
<div class="right mt5 ml5">Google+</div>
|
||||
</div>
|
||||
<br clear="all" />
|
||||
<div class="right">
|
||||
<a id="btn-band-setup-back" class="button-grey">BACK</a>
|
||||
<a id="btn-band-setup-save" class="button-orange">CREATE BAND</a>
|
||||
</div>
|
||||
<div class="clearall"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/template" id="template-band-setup-genres">
|
||||
<tr><td><input value="{id}" {checked} type="checkbox" />{description}</td></tr>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="template-band-invitation">
|
||||
<div user-id="{userId}" class="invitation">{userName}
|
||||
<a><%= image_tag "shared/icon_delete_sm.png", :size => "13x13" %></a>
|
||||
</div>
|
||||
</script>
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
#band-setup.screen.secondary layout="screen" layout-id="band/setup" layout-arg="id"
|
||||
.content-head
|
||||
.content-icon
|
||||
= image_tag "content/icon_bands.png", :size => "19x19"
|
||||
h1#band-setup-title
|
||||
| my band
|
||||
= render "screen_navigation"
|
||||
.content-body
|
||||
.content-body-scroller
|
||||
form#band-setup-form
|
||||
div style="display:block;"
|
||||
#band-setup-step-0.band-step.content-wrapper style="padding:10px 35px10px 35px;"
|
||||
h2 edit profile: basics
|
||||
table width="100%"
|
||||
tr
|
||||
td colspan="2"
|
||||
|
||||
tr#name_row
|
||||
td colspan="2"
|
||||
.band-photo.hidden
|
||||
span.field
|
||||
a.band-avatar-profile href="#"
|
||||
= image_tag "shared/avatar_generic_band.png", {:id => "band-avatar", :align=>"absmiddle", :height => 88, :width => 88 }
|
||||
span.field
|
||||
a#band-change-photo.small.ml20 href="#"
|
||||
| Upload band photo.
|
||||
|
||||
.band-name
|
||||
.field
|
||||
label for="band-name"
|
||||
| Band Name:
|
||||
input#band-name type="text" maxlength="1024" value=""
|
||||
/ td#tdBandWebsite[]
|
||||
/ .field
|
||||
/ label for="band-website"
|
||||
/ | Web Site:
|
||||
/ input#band-website[type="text" maxlength="4000" value=""]
|
||||
tr
|
||||
td.band-country
|
||||
.field
|
||||
label for="band-country"
|
||||
| Country:
|
||||
select#band-country
|
||||
td.band-biography rowspan="3"
|
||||
.field
|
||||
label for="band-biography"
|
||||
| Description / Bio:
|
||||
textarea#band-biography rows="8"
|
||||
tr
|
||||
td.band-region
|
||||
.field
|
||||
label for="band-region"
|
||||
| State/Region:
|
||||
select#band-region
|
||||
tr
|
||||
td.band-city
|
||||
.field
|
||||
label for="band-city"
|
||||
| City:
|
||||
select#band-city
|
||||
|
||||
/ td#tdBandGenres[valign="top"]
|
||||
/ .field
|
||||
/ label for="band-genres"
|
||||
/ | Genres:
|
||||
/ .band-setup-genres.w90
|
||||
/ table#band-genres[width="100%" cellpadding="10" cellspacing="6"]
|
||||
#band-setup-step-1.band-step.content-wrapper
|
||||
h2 edit profile: musical experience
|
||||
#band-setup-step-2.band-step.content-wrapper
|
||||
h2 edit profile: current interests
|
||||
#band-setup-step-3.band-step.content-wrapper
|
||||
h2 edit profile: online presence & performance samples
|
||||
#band-setup-step-4.band-step.content-wrapper
|
||||
h2 invite members
|
||||
br
|
||||
#band-setup-invite-musicians
|
||||
br
|
||||
br
|
||||
| If your bandmates are not on JamKazam yet, use any of the options below to invite them to join the service.
|
||||
br
|
||||
br
|
||||
.left.mr20
|
||||
.left
|
||||
a.btn-email-invitation
|
||||
= image_tag("content/icon_gmail.png", :size => "24x24", :align => "absmiddle")
|
||||
.right.mt5.ml5
|
||||
| E-mail
|
||||
.left.mr20
|
||||
.left
|
||||
a.btn-facebook-invitation
|
||||
= image_tag("content/icon_facebook.png", :size => "24x24", :align => "absmiddle")
|
||||
.right.mt5.ml5
|
||||
| Facebook
|
||||
.left.left
|
||||
.left
|
||||
a.btn-gmail-invitation
|
||||
= image_tag("content/icon_google.png", :size => "24x24", :align => "absmiddle")
|
||||
.right.mt5.ml5
|
||||
| Google+
|
||||
/ br clear="all"
|
||||
/ .right
|
||||
/ a#btn-band-setup-back.button-grey
|
||||
/ | BACK
|
||||
/ |
|
||||
/ a#btn-band-setup-save.button-orange
|
||||
/ | CREATE BAND
|
||||
/ .clearall
|
||||
|
||||
br clear="all"
|
||||
.right
|
||||
a#btn-band-setup-cancel.nav-button.button-grey
|
||||
| CANCEL
|
||||
a#btn-band-setup-back.nav-button.button-grey.hidden
|
||||
| BACK
|
||||
a#btn-band-setup-next.nav-button.button-orange
|
||||
| SAVE & NEXT
|
||||
.clearall
|
||||
|
||||
script#template-band-setup-genres type="text/template"
|
||||
tr
|
||||
tr
|
||||
td
|
||||
input value="{id}" {checked} type="checkbox"
|
||||
| {description}
|
||||
|
||||
script#template-band-invitation type="text/template"
|
||||
.invitation user-id="{userId}"
|
||||
| {userName}
|
||||
a
|
||||
img src="shared/icon_delete_sm.png" width="13" height="13"
|
||||
|
||||
|
||||
|
|
@ -131,7 +131,7 @@
|
|||
<input type="checkbox" id="intellectual-property" class="intellectual-property" />
|
||||
</div>
|
||||
<div id="divTerms" class="terms ml25">
|
||||
I agree that intellectual property ownership of any musical works created during this session shall be governed by the terms of the <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/" target="_blank">Creative Commons CC BY-NC-SA license</a> in accordance with the <a rel="external" href="http://www.jamkazam.com/corp/terms" target="_blank">JamKazam Terms of Service</a>.
|
||||
I agree that intellectual property ownership of any musical works created during this session shall be governed by the terms of the <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/" target="_blank">Creative Commons CC BY-NC-SA license</a> in accordance with the <a rel="external" href="https://www.jamkazam.com/corp/terms" target="_blank">JamKazam Terms of Service</a>.
|
||||
</div>
|
||||
</div>
|
||||
<br clear="all"/>
|
||||
|
|
|
|||
|
|
@ -140,20 +140,20 @@
|
|||
|
||||
<ul class="device_type">
|
||||
<li class="ftue-video-link first"
|
||||
external-link-win="http://www.youtube.com/watch?v=b1JrwGeUcOo"
|
||||
external-link-mac="http://www.youtube.com/watch?v=TRzb7OTlO-Q">
|
||||
external-link-win="https://www.youtube.com/watch?v=b1JrwGeUcOo"
|
||||
external-link-mac="https://www.youtube.com/watch?v=TRzb7OTlO-Q">
|
||||
AUDIO DEVICE WITH PORTS FOR INSTRUMENT OR MIC INPUT JACKS<br/>
|
||||
<p><%= image_tag "content/audio_capture_ftue.png", {:width => 243, :height => 70} %></p>
|
||||
</li>
|
||||
<li class="ftue-video-link"
|
||||
external-link-win="http://www.youtube.com/watch?v=IDrLa8TOXwQ"
|
||||
external-link-mac="http://www.youtube.com/watch?v=vIs7ArrjMpE">
|
||||
external-link-win="https://www.youtube.com/watch?v=IDrLa8TOXwQ"
|
||||
external-link-mac="https://www.youtube.com/watch?v=vIs7ArrjMpE">
|
||||
USB MICROPHONE<br/>
|
||||
<p><%= image_tag "content/microphone_ftue.png", {:width => 70, :height => 113} %></p>
|
||||
</li>
|
||||
<li class="ftue-video-link"
|
||||
external-link-win="http://www.youtube.com/watch?v=PCri4Xed4CA"
|
||||
external-link-mac="http://www.youtube.com/watch?v=Gatmd_ja47U">
|
||||
external-link-win="https://www.youtube.com/watch?v=PCri4Xed4CA"
|
||||
external-link-mac="https://www.youtube.com/watch?v=Gatmd_ja47U">
|
||||
COMPUTER'S BUILT-IN MIC & SPEAKERS/HEADPHONES<br/>
|
||||
<p><%= image_tag "content/computer_ftue.png", {:width => 118, :height => 105} %></p>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
#jamtrackScreen.screen.secondary.no-login-required layout='screen' layout-id='jamtrackBrowse'
|
||||
.content
|
||||
.content-head
|
||||
.content-icon=image_tag("content/icon_jamtracks.png", height:19, width:19 )
|
||||
h1 jamtracks
|
||||
=render "screen_navigation"
|
||||
.content-body
|
||||
=form_tag('', {:id => 'jamtrack-find-form', :class => 'inner-content'}) do
|
||||
=render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_JAMTRACK})
|
||||
.filter-body
|
||||
.content-body-scroller
|
||||
.profile-wrapper
|
||||
h2 shop for jamtracks
|
||||
table.generaltable
|
||||
thead
|
||||
tr
|
||||
th JAMTRACK
|
||||
th TRACKS INCLUDED / PREVIEW
|
||||
th.center SHOP
|
||||
tbody.jamtrack-content
|
||||
a.btn-next-pager href="/api/jamtracks?page=1" Next
|
||||
.end-of-jamtrack-list.end-of-list="No more Jamtracks"
|
||||
|
||||
script#template-jamtrack type='text/template'
|
||||
tr.jamtrack-record jamtrack-id="{{data.jamtrack.id}}"
|
||||
td.jamtrack-detail
|
||||
.detail-label
|
||||
| Title:
|
||||
.detail-value
|
||||
| {{data.jamtrack.name}}
|
||||
.clearall.detail-label
|
||||
| Original Artist:
|
||||
.detail-value
|
||||
| {{data.jamtrack.original_artist}}
|
||||
.clearall.detail-label
|
||||
| Genre:
|
||||
.detail-value
|
||||
| {{data.jamtrack.genres[0]}}
|
||||
.clearall.detail-label.extra.hidden
|
||||
| Writer(s):
|
||||
.detail-value.extra.hidden
|
||||
| {{data.jamtrack.songwriter}}
|
||||
.clearall.detail-label.extra.hidden
|
||||
| Publisher:
|
||||
.detail-value.extra.hidden
|
||||
| {{data.jamtrack.publisher}}
|
||||
td.jamtrack-tracks
|
||||
.detail-arrow
|
||||
.jamtrack-detail-btn.orange
|
||||
="{% if (data.expanded) { %}"
|
||||
| hide tracks
|
||||
a.details-arrow.arrow-up-orange
|
||||
="{% } else { %}"
|
||||
| preview all tracks
|
||||
a.details-arrow.arrow-down-orange
|
||||
="{% } %}"
|
||||
="{% _.each(data.jamtrack.tracks, function(track) { %}"
|
||||
.jamtrack-track.hidden jamtrack-track-id="{{track.id}}"
|
||||
/ .instrument-desc
|
||||
/ | {{track.instrument_desc}}
|
||||
/.track-instrument
|
||||
.jamtrack-preview
|
||||
.clearall
|
||||
="{% }); %}"
|
||||
td.jamtrack-action
|
||||
/ a.play-button href="#" data-jamtrack-id="{{data.jamtrack.id}}"
|
||||
/ =image_tag "shared/play_button.png"
|
||||
.jamtrack-price class="{{data.free_state}}"
|
||||
| {{"$ " + data.jamtrack.price}}
|
||||
.free-state.hidden
|
||||
| (first one is FREE)
|
||||
="{% if (data.jamtrack.purchased) { %}"
|
||||
a.jamtrack-add-cart-disabled.button-grey.button-disabled href="javascript:void(0)" PURCHASED
|
||||
="{% } else if (data.jamtrack.added_cart) { %}"
|
||||
a.jamtrack-add-cart-disabled.button-grey.button-disabled href="client#/shoppingCart" ALREADY IN CART
|
||||
="{% } else { %}"
|
||||
a.jamtrack-add-cart.button-orange href="#" data-jamtrack-id="{{data.jamtrack.id}}" ADD TO CART
|
||||
="{% }; %}"
|
||||
="{% if (data.jamtrack.sales_region==JK.AVAILABILITY_US) { %}"
|
||||
.jamtrack-license
|
||||
| This JamTrack available only to US customers.
|
||||
a.license-us-why.orange href="#" why?
|
||||
="{% }; %}"
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
#jamtrackScreen.screen.secondary.no-login-required layout='screen' layout-id='jamtrackBrowse'
|
||||
.content
|
||||
.content-head
|
||||
.content-icon=image_tag("content/icon_jamtracks.png", height:19, width:19 )
|
||||
h1 jamtracks
|
||||
=render "screen_navigation"
|
||||
.content-body
|
||||
=form_tag('', {:id => 'jamtrack-find-form', :class => 'inner-content'}) do
|
||||
=render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_JAMTRACK})
|
||||
.filter-body
|
||||
.content-body-scroller
|
||||
.profile-wrapper
|
||||
h2 shop for jamtracks
|
||||
table.generaltable.jamtrack-table
|
||||
thead
|
||||
tr
|
||||
th.jamtrack-detail JAMTRACK
|
||||
th.jamtrack-tracks TRACKS INCLUDED / PREVIEW
|
||||
th.jamtrack-action SHOP
|
||||
tbody.jamtrack-content
|
||||
a.btn-next-pager href="/api/jamtracks?page=1" Next
|
||||
.end-of-jamtrack-list.end-of-list="No more Jamtracks"
|
||||
|
||||
script#template-jamtrack type='text/template'
|
||||
tr.jamtrack-record jamtrack-id="{{data.jamtrack.id}}"
|
||||
td.jamtrack-detail
|
||||
.jamtrack-name
|
||||
| "{{data.jamtrack.name}}"
|
||||
.jamtrack-original-artist
|
||||
| by {{data.jamtrack.original_artist}}
|
||||
br clear="all"
|
||||
.clearall.detail-label.extra.hidden.song-writer
|
||||
| Songwriters:
|
||||
.detail-value.extra.hidden
|
||||
| {{data.jamtrack.songwriter}}
|
||||
.clearall.detail-label.extra.hidden
|
||||
| Publishers:
|
||||
.detail-value.extra.hidden
|
||||
| {{data.jamtrack.publisher}}
|
||||
.clearall.detail-label.extra.hidden
|
||||
| Genre:
|
||||
.detail-value.extra.hidden
|
||||
| {{data.jamtrack.genres[0]}}
|
||||
.clearall.detail-label.extra.hidden
|
||||
| Version:
|
||||
.detail-value.extra.hidden
|
||||
| {{data.jamtrack.recording_type}}
|
||||
td.jamtrack-tracks
|
||||
.detail-arrow
|
||||
.jamtrack-detail-btn
|
||||
="{% if (data.expanded) { %}"
|
||||
| hide tracks
|
||||
a.details-arrow.arrow-up
|
||||
="{% } else { %}"
|
||||
| show all tracks
|
||||
a.details-arrow.arrow-down
|
||||
="{% } %}"
|
||||
="{% _.each(data.jamtrack.tracks, function(track) { %}"
|
||||
.jamtrack-track.hidden jamtrack-track-id="{{track.id}}"
|
||||
/ .instrument-desc
|
||||
/ | {{track.instrument_desc}}
|
||||
/.track-instrument
|
||||
.jamtrack-preview
|
||||
.clearall
|
||||
="{% }); %}"
|
||||
td.jamtrack-action
|
||||
.jamtrack-action-container
|
||||
.jamtrack-actions
|
||||
/ a.play-button href="#" data-jamtrack-id="{{data.jamtrack.id}}"
|
||||
/ =image_tag "shared/play_button.png"
|
||||
.jamtrack-price class="{{data.free_state}}"
|
||||
| {{"$ " + data.jamtrack.price}}
|
||||
="{% if (data.is_free) { %}"
|
||||
a.jamtrack-add-cart.button-orange.is_free href="#" data-jamtrack-id="{{data.jamtrack.id}}" GET IT FREE!
|
||||
="{% } else if (data.jamtrack.purchased) { %}"
|
||||
a.jamtrack-add-cart-disabled.button-grey.button-disabled href="javascript:void(0)" PURCHASED
|
||||
="{% } else if (data.jamtrack.added_cart) { %}"
|
||||
a.jamtrack-add-cart-disabled.button-grey.button-disabled href="client#/shoppingCart" ALREADY IN CART
|
||||
="{% } else { %}"
|
||||
a.jamtrack-add-cart.button-orange href="#" data-jamtrack-id="{{data.jamtrack.id}}" ADD TO CART
|
||||
="{% }; %}"
|
||||
="{% if (data.jamtrack.sales_region==JK.AVAILABILITY_US) { %}"
|
||||
.jamtrack-license
|
||||
| This JamTrack available only to US customers.
|
||||
a.license-us-why.orange href="#" why?
|
||||
="{% }; %}"
|
||||
|
|
@ -163,11 +163,11 @@ div layout="screen" layout-id="order" id="orderScreen" class="screen secondary"
|
|||
.mt5
|
||||
span By placing your order, you agree to JamKazam's
|
||||
'
|
||||
a href="http://www.jamkazam.com/corp/terms" terms of service
|
||||
a href="/corp/terms" terms of service
|
||||
'
|
||||
span and
|
||||
'
|
||||
a href="http://www.jamkazam.com/corp/returns" returns policy
|
||||
a href="/corp/returns" returns policy
|
||||
span .
|
||||
.right.mt10
|
||||
a href="#" class="button-grey" HELP
|
||||
|
|
@ -279,11 +279,11 @@ script type='text/template' id='template-order-content'
|
|||
div style="text-align: left;"
|
||||
span By placing your order, you agree to JamKazam's
|
||||
'
|
||||
a href="http://www.jamkazam.com/corp/terms" terms of service
|
||||
a href="/corp/terms" terms of service
|
||||
'
|
||||
span and
|
||||
'
|
||||
a href="http://www.jamkazam.com/corp/returns" returns policy
|
||||
a href="/corp/returns" returns policy
|
||||
span .
|
||||
|
||||
script type='text/template' id='template-purchased-jam-track'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
div layout="screen" layout-id="redeemComplete" id="redeemCompleteScreen" class="screen secondary"
|
||||
.content
|
||||
.content-head
|
||||
.content-icon= image_tag("content/icon_shopping_cart.png", {:height => 19, :width => 19})
|
||||
h1 check out
|
||||
= render "screen_navigation"
|
||||
.content-body
|
||||
.content-body-scroller
|
||||
.content-wrapper
|
||||
.checkout-navigation-bar
|
||||
.checkout-complete-wrapper
|
||||
.no-purchases-prompt.hidden
|
||||
| You have not made any purchases recently. Why not go go
|
||||
a href="/client#/jamtrackBrowse" browse our collection of JamTracks
|
||||
| ?
|
||||
.thanks-panel
|
||||
|
||||
.jam-tracks-in-browser.hidden
|
||||
p Thank you for joining our community, and congratulations on getting your first JamTrack!
|
||||
p.why-download
|
||||
| JamTracks are full multi-track recordings with lots of special features, so they are not
|
||||
| just standard audio files. To play with your JamTrack, you'll need to download and install
|
||||
| our free Mac or Windows app. This is the last step in the process, and you'll be ready to play.
|
||||
| This free app also lets you play online in real time with other musicians over the Internet at no cost!
|
||||
|
||||
a.download-jamkazam-wrapper href="/downloads" rel="external"
|
||||
.download-jamkazam
|
||||
| Click Here to Get the Free JamKazam Application
|
||||
|
||||
.jam-tracks-in-client.hidden
|
||||
|
||||
h2 Congratulations on getting your JamTrack!
|
||||
|
||||
.thanks-detail.purchased-jam-track
|
||||
h2.purchased-jam-track-header status="in-progress"
|
||||
span.in-progress-msg Downloading Your JamTrack
|
||||
span.done-msg All purchased JamTracks have been downloaded successfully! You can now play them in a session.
|
||||
span.notice Note that you do not have to wait for this to complete in order to use your JamTrack later.
|
||||
br.clear
|
||||
ul.purchased-list
|
||||
.clearall.hidden
|
||||
.action-bar
|
||||
.right
|
||||
a.button-orange.checkout-done href="/client#/home" DONE
|
||||
.clearall
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
div layout="screen" layout-id="redeemSignup" id="redeemSignupScreen" class="screen secondary no-login-required"
|
||||
.content
|
||||
.content-head
|
||||
.content-icon= image_tag("content/icon_shopping_cart.png", {:height => 19, :width => 19})
|
||||
h1 check out
|
||||
= render "screen_navigation"
|
||||
.content-body
|
||||
.content-body-scroller
|
||||
.redeem-signup
|
||||
|
||||
.content-holder
|
||||
.already-signed-in
|
||||
h3 YOU ARE ALREADY LOGGED IN
|
||||
p.carry-on-prompt
|
||||
| You can go back to browsing.
|
||||
.actions
|
||||
a.btnNext.button-orange href="/client#/jamtrackBrowse" BROWSE JAMTRACKS
|
||||
.not-signed-in.prompt
|
||||
| To get your free
|
||||
span.jamtrack-name
|
||||
| JamTrack, join thousands of musicians in the JamKazam community by registering for your free account.
|
||||
.left-side
|
||||
.left-side-content
|
||||
= link_to image_tag("content/button_facebook_signup.png", {:width => 249, :height => 46}), '/auth/facebook', class: "signup-facebook"
|
||||
br clear="all"
|
||||
.field.terms_of_service
|
||||
input type="checkbox"
|
||||
label
|
||||
| I have read and agree to the JamKazam
|
||||
br
|
||||
= link_to "terms of service", corp_terms_path, rel: "external"
|
||||
|.
|
||||
br clear="all"
|
||||
|
||||
.right-side
|
||||
h3 OR SIGN UP USING YOUR EMAIL
|
||||
|
||||
.signup-form
|
||||
form.signup-form
|
||||
.input-elements
|
||||
.field
|
||||
label.inline First Name:
|
||||
input name='first_name' autofocus="true" type="text"
|
||||
.field
|
||||
label.inline Last Name:
|
||||
input name='last_name' type="text"
|
||||
.field
|
||||
label.inline Email:
|
||||
input name='email' type="text"
|
||||
.field
|
||||
label.inline Password:
|
||||
input name='password' autofocus="true" type="password"
|
||||
.field.terms_of_service
|
||||
input type="checkbox"
|
||||
label
|
||||
| I have read and agree to the JamKazam
|
||||
= link_to "terms of service", corp_terms_path, rel: "external"
|
||||
|.
|
||||
.field.recaptcha style="display:none"
|
||||
- if Rails.application.config.recaptcha_enable
|
||||
#recaptcha_select name="recaptcha_response_field" class="g-recaptcha" data-sitekey=Rails.application.config.recaptcha_public_key
|
||||
.actions
|
||||
input.button-orange.signup-submit type="submit" value="SIGNUP"
|
||||
|
||||
= link_to "Already have a JamKazam account? Sign in", "#", class: 'signin'
|
||||
|
||||
br clear='all'
|
||||
|
|
@ -37,13 +37,15 @@
|
|||
<%= render "band_setup_photo" %>
|
||||
<%= render "users/feed_music_session_ajax" %>
|
||||
<%= render "users/feed_recording_ajax" %>
|
||||
<%= render "jamtrack" %>
|
||||
<%= render "jamtrack_browse" %>
|
||||
<%= render "jamtrack_landing" %>
|
||||
<%= render "shopping_cart" %>
|
||||
<%= render "checkout_signin" %>
|
||||
<%= render "checkout_payment" %>
|
||||
<%= render "checkout_order" %>
|
||||
<%= render "checkout_complete" %>
|
||||
<%= render "redeem_signup" %>
|
||||
<%= render "redeem_complete" %>
|
||||
<%= render "order" %>
|
||||
<%= render "feed" %>
|
||||
<%= render "bands" %>
|
||||
|
|
@ -114,12 +116,14 @@
|
|||
JK.currentUserName = '<%= current_user.name %>';
|
||||
JK.currentUserMusician = '<%= current_user.musician %>';
|
||||
JK.currentUserAdmin = <%= current_user.admin %>;
|
||||
JK.currentUserFreeJamTrack = <%= APP_CONFIG.one_free_jamtrack_per_user && current_user.has_redeemable_jamtrack %>
|
||||
<% else %>
|
||||
JK.currentUserId = null;
|
||||
JK.currentUserAvatarUrl = null;
|
||||
JK.currentUserName = null;
|
||||
JK.currentUserMusician = null;
|
||||
JK.currentUserAdmin = false;
|
||||
JK.currentUserFreeJamTrack = <%= APP_CONFIG.one_free_jamtrack_per_user && anonymous_user.nil? ? false : anonymous_user.has_redeemable_jamtrack%>
|
||||
<% end %>
|
||||
|
||||
|
||||
|
|
@ -301,6 +305,12 @@
|
|||
// var findBandScreen = new JK.FindBandScreen(JK.app);
|
||||
// findBandScreen.initialize();
|
||||
|
||||
var redeemSignUpScreen = new JK.RedeemSignUpScreen(JK.app);
|
||||
redeemSignUpScreen.initialize();
|
||||
|
||||
var redeemCompleteScreen = new JK.RedeemCompleteScreen(JK.app);
|
||||
redeemCompleteScreen.initialize();
|
||||
|
||||
var sessionScreen = new JK.SessionScreen(JK.app);
|
||||
sessionScreen.initialize(localRecordingsDialog, recordingFinishedDialog, JK.FriendSelectorDialogInstance);
|
||||
|
||||
|
|
@ -328,6 +338,10 @@
|
|||
var singlePlayerProfileGuardDialog = new JK.SinglePlayerProfileGuardDialog(JK.app);
|
||||
singlePlayerProfileGuardDialog.initialize();
|
||||
|
||||
var signinDialog = new JK.SigninDialog(JK.app);
|
||||
signinDialog.initialize();
|
||||
JK.SigninPage(); // initialize signin helper
|
||||
|
||||
// do a client update early check upon initialization
|
||||
JK.ClientUpdateInstance.check()
|
||||
|
||||
|
|
|
|||
|
|
@ -14,18 +14,18 @@
|
|||
|
||||
|
||||
%ul.device_type
|
||||
%li.ftue-video-link.first{'external-link-win'=>"http://www.youtube.com/watch?v=b1JrwGeUcOo", 'external-link-mac'=>"http://www.youtube.com/watch?v=TRzb7OTlO-Q"}
|
||||
%li.ftue-video-link.first{'external-link-win'=>"https://www.youtube.com/watch?v=b1JrwGeUcOo", 'external-link-mac'=>"https://www.youtube.com/watch?v=TRzb7OTlO-Q"}
|
||||
AUDIO DEVICE WITH PORTS FOR INSTRUMENT OR MIC INPUT JACKS
|
||||
%br
|
||||
%p
|
||||
= image_tag "content/audio_capture_ftue.png", {:width => 243, :height => 70}
|
||||
|
||||
%li.ftue-video-link{'external-link-win'=>"http://www.youtube.com/watch?v=IDrLa8TOXwQ",'external-link-mac'=>"http://www.youtube.com/watch?v=vIs7ArrjMpE"}
|
||||
%li.ftue-video-link{'external-link-win'=>"https://www.youtube.com/watch?v=IDrLa8TOXwQ",'external-link-mac'=>"https://www.youtube.com/watch?v=vIs7ArrjMpE"}
|
||||
USB MICROPHONE
|
||||
%br
|
||||
%p
|
||||
= image_tag "content/microphone_ftue.png", {:width => 70, :height => 113}
|
||||
%li.ftue-video-link{'external-link-win'=>"http://www.youtube.com/watch?v=PCri4Xed4CA",'external-link-mac'=>"http://www.youtube.com/watch?v=Gatmd_ja47U"}
|
||||
%li.ftue-video-link{'external-link-win'=>"https://www.youtube.com/watch?v=PCri4Xed4CA",'external-link-mac'=>"https://www.youtube.com/watch?v=Gatmd_ja47U"}
|
||||
COMPUTER'S BUILT-IN MIC & SPEAKERS/HEADPHONES
|
||||
%br
|
||||
%p
|
||||
|
|
|
|||
|
|
@ -18,20 +18,20 @@
|
|||
|
||||
<h3>Classical: Pachelbel’s “Canon in D”</h3>
|
||||
<ul>
|
||||
<li><a href="http://www.jamkazam.com/recordings/b3071f33-4514-4f05-8b36-8db8edeab23e" target="_blank">Real-Time Streamed Recording</a></li>
|
||||
<li><a href="http://www.jamkazam.com/recordings/70e9a449-b142-436c-9fb0-cec133a0b429" target="_blank">Mastered Recording</a></li>
|
||||
<li><a href="https://www.jamkazam.com/recordings/b3071f33-4514-4f05-8b36-8db8edeab23e" target="_blank">Real-Time Streamed Recording</a></li>
|
||||
<li><a href="https://www.jamkazam.com/recordings/70e9a449-b142-436c-9fb0-cec133a0b429" target="_blank">Mastered Recording</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3>Rock: Poison’s “Nothin’ But a Good Time”</h3>
|
||||
<ul>
|
||||
<li><a href="http://www.jamkazam.com/recordings/c9e5aec1-662e-4e75-89a9-546f6399c342" target="_blank">Real-Time Streamed Recording</a></li>
|
||||
<li><a href="http://www.jamkazam.com/recordings/05a9ae58-f183-43ae-b57d-54ccf932d15c" target="_blank">Mastered Recording</a></li>
|
||||
<li><a href="https://www.jamkazam.com/recordings/c9e5aec1-662e-4e75-89a9-546f6399c342" target="_blank">Real-Time Streamed Recording</a></li>
|
||||
<li><a href="https://www.jamkazam.com/recordings/05a9ae58-f183-43ae-b57d-54ccf932d15c" target="_blank">Mastered Recording</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3>Jazz: Jimmy Van Heusen’s and Johnny Burke’s “But Beautiful”</h3>
|
||||
<ul>
|
||||
<li><a href="http://www.jamkazam.com/recordings/eaf88dd0-4b66-4e2b-a856-7e312c392cff" target="_blank">Real-Time Streamed Recording</a></li>
|
||||
<li><a href="http://www.jamkazam.com/recordings/df68065a-8159-4315-957f-9530549dbbac" target="_blank">Mastered Recording</a></li>
|
||||
<li><a href="https://www.jamkazam.com/recordings/eaf88dd0-4b66-4e2b-a856-7e312c392cff" target="_blank">Real-Time Streamed Recording</a></li>
|
||||
<li><a href="https://www.jamkazam.com/recordings/df68065a-8159-4315-957f-9530549dbbac" target="_blank">Mastered Recording</a></li>
|
||||
</ul>
|
||||
|
|
@ -69,7 +69,7 @@
|
|||
| There is a lot you can do with JamKazam, and more great features available every week. Check the
|
||||
following link for a list of videos and other resources you can use to take advantage of everything that’s
|
||||
available:
|
||||
a rel="external" purpose="youtube-tutorials" href="http://www.youtube.com/channel/UC38nc9MMZgExJAd7ca3rkUA" JamKazam Tutorials & Resources
|
||||
a rel="external" purpose="youtube-tutorials" href="https://www.youtube.com/channel/UC38nc9MMZgExJAd7ca3rkUA" JamKazam Tutorials & Resources
|
||||
br clear="both"
|
||||
.row.dialog-buttons
|
||||
.buttons
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<!-- inner wrapper -->
|
||||
<div class="overlay-video-inner">
|
||||
<iframe id="video-dialog-iframe" width="550" height="309" frameborder="0" allowfullscreen></iframe>
|
||||
<iframe id="video-dialog-iframe" width="550" height="309" frameborder="0" allowfullscreen="allowfullscreen"></iframe>
|
||||
</div>
|
||||
<!-- end inner -->
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue