diff --git a/admin/Gemfile b/admin/Gemfile index c66e1b869..75632d35c 100644 --- a/admin/Gemfile +++ b/admin/Gemfile @@ -59,7 +59,7 @@ gem 'resque' gem 'resque-retry' gem 'resque-failed-job-mailer' gem 'resque-lonely_job', '~> 1.0.0' -gem 'eventmachine', '1.0.4' +gem 'eventmachine', '1.2.3' gem 'amqp', '0.9.8' #gem 'logging-rails', :require => 'logging/rails' gem 'pg_migrate' @@ -82,9 +82,9 @@ gem 'stripe' gem 'zip-codes' gem 'email_validator' -group :libv8 do - gem 'libv8', "~> 4.5.95" -end +#group :libv8 do +# gem 'libv8', "~> 4.5.95" +#end # To use Jbuilder templates for JSON diff --git a/admin/app/admin/inactive_jamclass_users.rb b/admin/app/admin/inactive_jamclass_users.rb new file mode 100644 index 000000000..c5e5bb9aa --- /dev/null +++ b/admin/app/admin/inactive_jamclass_users.rb @@ -0,0 +1,40 @@ +ActiveAdmin.register JamRuby::User, :as => 'InactiveJamClassUsers' do + + menu :label => 'Inactive JamClass Users w/o Credits', :parent => 'JamClass' + + config.sort_order = 'created_at' + config.batch_actions = false + config.per_page = 100 + config.paginate = true + config.filters = false + + scope("All", default: true) { |scope| scope.includes(:taken_lessons => :music_session).select("distinct(users.id), users.email, users.first_name, users.last_name").joins("inner join posa_cards on posa_cards.user_id = users.id inner join lesson_sessions on lesson_sessions.user_id = users.id left outer join music_sessions on music_sessions.lesson_session_id = music_sessions.id ").where("jamclass_credits = 0") } + + index do + column "Name" do |user| + span do + link_to "#{user.name} (#{user.email})", "#{Rails.application.config.external_root_url}/client#/profile/#{user.id}" + end + end + column "POSA" do |user| + span do + posa = user.posa_cards[0] + if posa.lesson_package_type + posa.lesson_package_type.id + else + posa.card_type + end + end + end + column "Last Session" do |user| + span do + if user.taken_lessons.length == 0 + "none yet" + else + most_recent_lesson = user.taken_lessons.order('created_at desc')[0] + link_to most_recent_lesson.scheduled_start, admin_lesson_session_path(most_recent_lesson) + end + end + end + end +end \ No newline at end of file diff --git a/admin/app/admin/inactive_posa_jamclass.rb b/admin/app/admin/inactive_posa_jamclass.rb new file mode 100644 index 000000000..5b86906e3 --- /dev/null +++ b/admin/app/admin/inactive_posa_jamclass.rb @@ -0,0 +1,45 @@ +ActiveAdmin.register JamRuby::User, :as => 'InactiveJamClassPOSAUsers' do + + menu :label => 'Inactive JamClass Users w/ Credits', :parent => 'JamClass' + + config.sort_order = 'created_at' + config.batch_actions = false + config.per_page = 100 + config.paginate = true + config.filters = false + + scope("All", default: true) { |scope| scope.includes(:taken_lessons => :music_session).select("distinct(users.id), users.email, users.first_name, users.last_name, users.jamclass_credits").joins("inner join posa_cards on posa_cards.user_id = users.id left outer join lesson_sessions on lesson_sessions.user_id = users.id left outer join music_sessions on music_sessions.lesson_session_id = music_sessions.id ").where("jamclass_credits > 0 AND music_sessions.id IS NULL OR music_sessions.scheduled_start < ?", Time.now - 7.days) } + + index do + column "Name" do |user| + span do + link_to "#{user.name} (#{user.email})", "#{Rails.application.config.external_root_url}/client#/profile/#{user.id}" + end + end + column "POSA" do |user| + span do + posa = user.posa_cards[0] + if posa.lesson_package_type + posa.lesson_package_type.id + else + posa.card_type + end + end + end + column "Credits" do |user| + span do + user.jamclass_credits + end + end + column "Last Session" do |user| + span do + if user.taken_lessons.length == 0 + "none yet" + else + most_recent_lesson = user.taken_lessons.order('created_at desc')[0] + link_to most_recent_lesson.scheduled_start, admin_lesson_session_path(most_recent_lesson) + end + end + end + end +end \ No newline at end of file diff --git a/admin/app/admin/lesson_session.rb b/admin/app/admin/lesson_session.rb index cd4458a43..4e781e524 100644 --- a/admin/app/admin/lesson_session.rb +++ b/admin/app/admin/lesson_session.rb @@ -17,10 +17,16 @@ ActiveAdmin.register JamRuby::LessonSession, :as => 'LessonSessions' do scope("Completed") { |scope| scope.unscoped.completed.order('created_at desc') } index do - column "User Link" do |lesson_session| + column "Actions" do |teacher| + links = ''.html_safe + links << link_to("View", resource_path(teacher), :class => "member_link view_link") + links << link_to("Edit", edit_resource_path(teacher), :class => "member_link edit_link") + links + end + column "App Link" do |lesson_session| lesson_booking = lesson_session.lesson_booking span do - link_to "Web URL", "#{Rails.application.config.external_root_url}/client#/jamclass/lesson-booking/#{lesson_booking.id}" + link_to "link", "#{Rails.application.config.external_root_url}/client#/jamclass/lesson-booking/#{lesson_booking.id}" end end column "Status" do |lesson_session| @@ -58,10 +64,10 @@ ActiveAdmin.register JamRuby::LessonSession, :as => 'LessonSessions' do show do attributes_table do - row "User Link" do |lesson_session| + row "App Link" do |lesson_session| lesson_booking = lesson_session.lesson_booking span do - link_to "Web URL", "#{Rails.application.config.external_root_url}/client#/jamclass/lesson-booking/#{lesson_booking.id}" + link_to "link", "#{Rails.application.config.external_root_url}/client#/jamclass/lesson-booking/#{lesson_booking.id}" end end row "Status" do |lesson_session| @@ -82,13 +88,13 @@ ActiveAdmin.register JamRuby::LessonSession, :as => 'LessonSessions' do row "Teacher" do |lesson_session| teacher = lesson_session.teacher span do - link_to "#{teacher.name} (#{teacher.email})", "#{Rails.application.config.external_root_url}/client#/profile/teacher/#{teacher.id}" + link_to teacher.admin_name, "#{Rails.application.config.external_root_url}/client#/profile/teacher/#{teacher.id}" end end row "Student" do |lesson_session| student = lesson_session.student span do - link_to "#{student.name} (#{student.email})", "#{Rails.application.config.external_root_url}/client#/profile/#{student.id}" + link_to student.admin_name, "#{Rails.application.config.external_root_url}/client#/profile/#{student.id}" end end row "Followup Emails Sent" do |lesson_session| @@ -111,6 +117,11 @@ ActiveAdmin.register JamRuby::LessonSession, :as => 'LessonSessions' do lesson_session.timed_description end end + row "Session" do |lesson_session| + span do + link_to "Session", lesson_session.music_session.admin_url + end + end row "Analysis" do |lesson_session| if lesson_session.analysed span style: "white-space: pre;" do diff --git a/admin/app/admin/music_session_history.rb b/admin/app/admin/music_session.rb similarity index 61% rename from admin/app/admin/music_session_history.rb rename to admin/app/admin/music_session.rb index c7eb5fcb7..80b5dafd5 100644 --- a/admin/app/admin/music_session_history.rb +++ b/admin/app/admin/music_session.rb @@ -60,4 +60,51 @@ ActiveAdmin.register JamRuby::MusicSession, :as => 'Music Session' do end end + show do + attributes_table do + row :id + row :name + row :description + row :creator do |session| + link_to(session.creator.admin_name, session.creator.admin_url) + end + row :created_at + row :started_at + row :session_ended_at do |session| session.session_removed_at end + row :genre + row :recurring_mode + row :timezone + row :fan_access + row :music_access + row :approval_required + row :open_rsvps + row :is_unstructured_rsv + row :canceled + row :lesson_session do |session| + lesson_session = session.lesson_session + if lesson_session + link_to("Lesson", lesson_session.admin_url) + else + '' + end + end + row 'Session Attendances' do |session| + + table_for(msuh = session.music_session_user_histories) do + column :user do |msuh| msuh.user.admin_name end + column :joined do |msuh| msuh.created_at.strftime('%b %d %Y, %H:%M') end + column :duration do |msuh| "#{msuh.duration_minutes.round} minutes" end + column :perf_data do |msuh| + unless (uu = msuh.perf_uri).blank? + link_to('Per Data Link', uu) + else + 'No Perf Data' + end + end + end + + end + end + end + end diff --git a/admin/app/admin/posa_card_upload.rb b/admin/app/admin/posa_card_upload.rb index 75353ca6a..784a325c3 100644 --- a/admin/app/admin/posa_card_upload.rb +++ b/admin/app/admin/posa_card_upload.rb @@ -10,15 +10,31 @@ ActiveAdmin.register_page "POSA Card Uploads" do file = params[:jam_ruby_posa_card][:csv] array_of_arrays = CSV.read(file.tempfile.path) array_of_arrays.each do |row| - if row.length != 1 - raise "UKNONWN CSV FORMAT! Must be 1 column" + if row.length != 4 + raise "UKNONWN CSV FORMAT! Must be 4 columns" end code = row[0] + lesson_package_type = row[1] + preactivate = row[2].strip == "true" + requires_purchase = row[3].strip == "true" posa_card = PosaCard.new posa_card.code = code + posa_card.lesson_package_type = LessonPackageType.find(lesson_package_type) + posa_card.preactivate = preactivate + posa_card.requires_purchase = requires_purchase + posa_card.purchased = !requires_purchase posa_card.card_type = params[:jam_ruby_posa_card][:card_type] + + + if posa_card.card_type == PosaCard::JAM_CLASS_4 + posa_card.is_lesson = true + posa_card.credits = 4 + elsif posa_card.card_type == PosaCard::JAM_CLASS_2 + posa_card.is_lesson = true + posa_card.credits = 2 + end posa_card.origin = file .original_filename posa_card.save! end diff --git a/admin/app/admin/teachers.rb b/admin/app/admin/teachers.rb index e54718565..854fcaeae 100644 --- a/admin/app/admin/teachers.rb +++ b/admin/app/admin/teachers.rb @@ -45,7 +45,7 @@ ActiveAdmin.register JamRuby::Teacher, :as => 'Teachers' do end end -=begin + column "Background Check" do |teacher| div do if teacher.background_check_at @@ -56,25 +56,25 @@ ActiveAdmin.register JamRuby::Teacher, :as => 'Teachers' do br end span do - link_to(mark_background_check_admin_teacher_path(teacher.id), {confirm: "Mark as background checked?"}) do - "mark as checked" + link_to(edit_admin_teacher_background_check_path(teacher.id)) do + "update background check" end end else span do - '' + 'NO' end span do br end span do - link_to("mark as checked", mark_background_check_admin_teacher_path(teacher.id), {confirm: "Mark as background checked?"}) + link_to("update background check", edit_admin_teacher_background_check_path(teacher.id)) end end end end -=end + column "Session Ready" do |teacher| div do if teacher.ready_for_session_at diff --git a/admin/app/admin/user_background_check.rb b/admin/app/admin/user_background_check.rb new file mode 100644 index 000000000..0d112ee23 --- /dev/null +++ b/admin/app/admin/user_background_check.rb @@ -0,0 +1,31 @@ +ActiveAdmin.register JamRuby::Teacher, :as => 'TeacherBackgroundCheck' do + + + config.filters = false + menu :label => 'Teacher Background Check', :parent => 'JamClass' + + + + form do |f| + f.inputs 'Set Background Check' do + f.input :background_check_at, as: :date_select + end + f.actions + end + + + index do + column "Actions" do |teacher| + links = ''.html_safe + links << link_to("View", resource_path(teacher), :class => "member_link view_link") + links << link_to("Edit", edit_resource_path(teacher), :class => "member_link edit_link") + links + end + + column 'User' do |oo| + oo.user.email + end + end + + +end diff --git a/admin/config/application.rb b/admin/config/application.rb index 04ac0ef94..e9b2f6d4f 100644 --- a/admin/config/application.rb +++ b/admin/config/application.rb @@ -87,7 +87,7 @@ module JamAdmin config.recurly_root_url = 'https://jamkazam-development.recurly.com' # where is rabbitmq? - config.rabbitmq_host = "localhost" + config.rabbitmq_host = "127.0.0.1" config.rabbitmq_port = 5672 # set to false to instead use amazon. You will also need to supply amazon secrets diff --git a/admin/config/initializers/jam_ruby_teacher.rb b/admin/config/initializers/jam_ruby_teacher.rb index f855ae238..5a9cf3442 100644 --- a/admin/config/initializers/jam_ruby_teacher.rb +++ b/admin/config/initializers/jam_ruby_teacher.rb @@ -1,5 +1,5 @@ class JamRuby::Teacher - attr_accessible :short_bio, as: :admin + attr_accessible :short_bio, :background_check_at, as: :admin end diff --git a/admin/public/404.html b/admin/public/404.html deleted file mode 100644 index 9a48320a5..000000000 --- a/admin/public/404.html +++ /dev/null @@ -1,26 +0,0 @@ - - -
-You may have mistyped the address or the page may have moved.
-Maybe you tried to change something you didn't have access to.
-{explanation} @@ -531,7 +540,7 @@ UserStore = context.UserStore
` else if this.state.lesson.payment_style == 'weekly' bookingInfo = `You are booking a weekly recurring series of {lesson_length}-minute - lessons, to be paid individually as each lesson is taken, until cancelled.
` + lessons for ${this.bookedPrice()}, to be paid individually as each lesson is taken, until cancelled.` bookingDetail = `Your card will be charged on the day of each lesson. If you need to cancel a lesson, you must do so at least 24 hours before the lesson is scheduled, or you will be charged for the lesson in full. @@ -542,7 +551,7 @@ UserStore = context.UserStore
` else if this.state.lesson.payment_style == 'monthly' bookingInfo = `You are booking a weekly recurring series of {lesson_length}-minute - lessons, to be paid for monthly until cancelled.
` + lessons for ${this.bookedPrice()}, to be paid for monthly until cancelled.` bookingDetail = `
Your card will be charged on the first day of each month. Canceling individual lessons does not earn a
refund when buying monthly. To cancel, you must cancel at least 24 hours before the beginning of the
diff --git a/web/app/assets/javascripts/react-components/TeacherProfile.js.jsx.coffee b/web/app/assets/javascripts/react-components/TeacherProfile.js.jsx.coffee
index 43d0a0902..900c737fd 100644
--- a/web/app/assets/javascripts/react-components/TeacherProfile.js.jsx.coffee
+++ b/web/app/assets/javascripts/react-components/TeacherProfile.js.jsx.coffee
@@ -81,7 +81,7 @@ proficiencyDescriptionMap = {
# mount it
@profileClipboard = new Clipboard($profileLink.get(0), {
text: =>
- return context.JK.makeAbsolute('/client#/teacher/profile/' + @state.user.teacher?.id)
+ return context.JK.makeAbsolute('/client#/teacher/profile/' + @state.user.id)
})
else if $profileLink.length == 0 && @profileClipboard?
@profileClipboard.destroy()
@@ -245,10 +245,15 @@ proficiencyDescriptionMap = {
biography = biography.replace(/\n/g, "
")
- `

`
if !school_on_school && (!@state.user? || @state.user.jamclass_credits > 0 || @state.user.remaining_test_drives > 0 || @state.user['can_buy_test_drive?'])
bookTestDriveBtn = `BOOK TESTDRIVE LESSON`
else
bookSingleBtn = `BOOK LESSON`
resultsJsx.push(`Enter the 10-digit code you received in your email and click the Activate button below.
` + else + form = + `` + instruments = `Enter the 10-digit code you received in your email and click the Activate button below.
` + + + classes = classNames({'redeem-container': true, 'not-logged-in': !context.JK.currentUserId?, 'logged-in': context.JK.currentUserId? }) + `“Enter the 10-digit code from the back of your gift card and click the Redeem button below.
` + instruments = `Enter the 10-digit code from the back of your gift card and click the Redeem button below.
` classes = classNames({'redeem-container': true, 'not-logged-in': !context.JK.currentUserId?, 'logged-in': context.JK.currentUserId? }) @@ -121,10 +128,13 @@ badCode = 'This is not a valid code. Please carefully re-enter the code and try $code = $root.find('input[name="code"]') code = $code.val() + + @setState({processing:true}) + rest.redeemGiftCard({gift_card: code}) .done((response) => - @setState({formErrors: null, processing:false, done: true, gifted_jamtracks: response.gifted_jamtracks, gifted_jamclass: response.gifted_jamclass}) + @setState({formErrors: null, processing:false, done: true, gifted_jamtracks: response.gifted_jamtracks, gifted_jamclass: response.gifted_jamclass, purchase_required: response.purchase_required}) ).fail((jqXHR) => @setState({processing:false}) @@ -161,7 +171,7 @@ badCode = 'This is not a valid code. Please carefully re-enter the code and try rest.signup({email: email, password: password, gift_card: code, terms: terms}) .done((response) => - @setState({formErrors: null, processing:false, done: true, gifted_jamtracks: response.gifted_jamtracks, gifted_jamclass: response.gifted_jamclass}) + @setState({formErrors: null, processing:false, done: true, gifted_jamtracks: response.gifted_jamtracks, gifted_jamclass: response.gifted_jamclass, purchase_required: response.purchase_required}) ).fail((jqXHR) => @setState({processing:false}) diff --git a/web/app/assets/javascripts/react-components/mixins/PostProcessorMixin.js.coffee b/web/app/assets/javascripts/react-components/mixins/PostProcessorMixin.js.coffee index c61027267..45d7354c8 100644 --- a/web/app/assets/javascripts/react-components/mixins/PostProcessorMixin.js.coffee +++ b/web/app/assets/javascripts/react-components/mixins/PostProcessorMixin.js.coffee @@ -41,9 +41,9 @@ teacherActions = window.JK.Actions.Teacher else if lesson.status == 'canceled' lesson.displayStatus = 'Canceled' if lesson.student_canceled - lesson.displayStatus = 'Canceled (Student)' + lesson.displayStatus = 'Canceled (by Student)' else if lesson.teacher_canceled - lesson.displayStatus = 'Canceled (Teacher)' + lesson.displayStatus = 'Canceled (by Teacher)' else if lesson.status == 'suspended' lesson.displayStatus = 'Suspended' @@ -60,15 +60,15 @@ teacherActions = window.JK.Actions.Teacher if lesson.analysis?.teacher_analysis?.missed && lesson.analysis?.student_analysis?.missed lesson.missedRole = 'both student and teacher' lesson.missedUser = lesson.teacher - lesson.displayStatus = 'Missed (Both)' + lesson.displayStatus = 'Missed (by Both)' else if lesson.analysis?.teacher_analysis?.missed lesson.missedRole = 'the teacher' lesson.missedUser = lesson.teacher - lesson.displayStatus = 'Missed (Teacher)' + lesson.displayStatus = 'Missed (by Teacher)' else if lesson.analysis?.student_analysis?.missed lesson.missedRole = 'the student' lesson.missedUser = lesson.student - lesson.displayStatus = 'Missed (Student)' + lesson.displayStatus = 'Missed (by Student)' else lesson.displayStatus = 'Missed' diff --git a/web/app/assets/stylesheets/client/react-components/TeacherProfile.scss b/web/app/assets/stylesheets/client/react-components/TeacherProfile.scss index b1f2fbcec..2148a3454 100644 --- a/web/app/assets/stylesheets/client/react-components/TeacherProfile.scss +++ b/web/app/assets/stylesheets/client/react-components/TeacherProfile.scss @@ -62,6 +62,14 @@ .backgroundCheck { margin-top:20px; + img { + margin-left: 10px; + position: relative; + top: 4px; + } + .background-check-time { + margin-top:10px; + } } .introductory-video { diff --git a/web/app/assets/stylesheets/client/react-components/TeacherSearch.scss b/web/app/assets/stylesheets/client/react-components/TeacherSearch.scss index 9353e2d20..ee0b183d1 100644 --- a/web/app/assets/stylesheets/client/react-components/TeacherSearch.scss +++ b/web/app/assets/stylesheets/client/react-components/TeacherSearch.scss @@ -98,6 +98,11 @@ } } + .background-check { + position: absolute; + top: 34px; + left: 24px; + } .user-avatar { text-align:center; float:left; diff --git a/web/app/assets/stylesheets/landings/account_activate.scss b/web/app/assets/stylesheets/landings/account_activate.scss new file mode 100644 index 000000000..9afa413ed --- /dev/null +++ b/web/app/assets/stylesheets/landings/account_activate.scss @@ -0,0 +1,90 @@ +@import "client/common"; + +body.web.account_activate { + + h2 { + margin-bottom:20px; + } + + label{ + margin-bottom:4px; + color:$ColorTextTypical; + } + + input{ + margin-bottom:20px; + width:200px; + } + + .redeem-container { + margin-left:350px; + width:400px; + padding-top:20px; + + &.logged-in { + button { + margin-top:10px !important; + } + } + + &.not-logged-in { + + } + } + .redeem-content { + + } + p.instructions { + line-height:125%; + color:$ColorTextTypical; + margin-bottom:20px; + } + + button { + display:block !important; + height: 29px !important; + margin-bottom: 10px; + margin-right: 0px; + font-size: 16px !important; + padding: 7px 3px !important; + line-height:inherit !important; + margin-left:2px !important; + margin-top:15px; + } + + .icheckbox_minimal { + float: left; + top: -2px; + margin-left: 0; + margin-right:10px; + } + + .errors { + font-size:14px; + height:20px; + margin:0; + visibility: hidden; + color: red; + font-weight: bold; + + &.active { + visibility: visible; + } + } + + form { + margin-bottom:20px; + } + .terms-help { + float:left; + margin-top:-5px; + font-size:12px; + width:178px; + } + + .done-action { + margin-top: 20px; + line-height: 125%; + } + +} \ No newline at end of file diff --git a/web/app/controllers/api_music_sessions_controller.rb b/web/app/controllers/api_music_sessions_controller.rb index c63445f97..a4d255149 100644 --- a/web/app/controllers/api_music_sessions_controller.rb +++ b/web/app/controllers/api_music_sessions_controller.rb @@ -343,6 +343,35 @@ class ApiMusicSessionsController < ApiController end render :json => {}, :status => :ok end + + + begin + + lesson_link = nil + session_link = @history.music_session.admin_url + if @history.music_session.lesson_session + session_type = "Lesson" + lesson_link = @history.music_session.lesson_session.admin_url + else + session_type = "Session" + end + + + subject = "#{current_user.name} Rated Their #{session_type}!" + body = "Session Type: #{session_type}\n" + body << "Session Rating: #{@history.good_rating? ? "Good" : "Bad"}\n" + body << "User: #{current_user.email}\n" + body << "Music Session URL: #{session_link}\n" + if lesson_link + body << "Lesson URL: #{lesson_link}\n" + end + body << "Session Comments: #{@history.rating_comment}\n" + + AdminMailer.jamclass_alerts({subject: subject, body: body}).deliver_now + rescue Exception => e + logger.error("Exception sending out ratings email. Boo #{e}") + end + elsif request.get? render :json => { :should_rate_session => @history.should_rate_session? }, :status => :ok end diff --git a/web/app/controllers/api_users_controller.rb b/web/app/controllers/api_users_controller.rb index 311d6cbbf..e0df0a195 100644 --- a/web/app/controllers/api_users_controller.rb +++ b/web/app/controllers/api_users_controller.rb @@ -25,9 +25,10 @@ class ApiUsersController < ApiController end def calendar - @user=lookup_user - ics = CalendarManager.new.create_ics_feed(@user) - send_data ics, :filename => 'JamKazam', :disposition => 'inline', :type => "text/calendar" + #@user=lookup_user + #ics = CalendarManager.new.create_ics_feed(@user) + #send_data ics, :filename => 'JamKazam', :disposition => 'inline', :type => "text/calendar" + render :json => {}, :status => 200 end def show @@ -1015,12 +1016,12 @@ class ApiUsersController < ApiController if @posa_card.errors.any? respond_with_model(@posa_card) else - if @posa_card.card_type == PosaCard::JAM_CLASS_4 - render json: {gifted_jamclass: 4}, status: 200 + if @posa_card.is_lesson_posa_card? + render json: {gifted_jamclass: @posa_card.credits}, status: 200 elsif @posa_card.card_type == PosaCard::JAM_TRACKS_10 - render json: {gifted_jamtracks: 10}, status: 200 + render json: {gifted_jamtracks: @posa_card.credits}, status: 200 elsif @posa_card.card_type == PosaCard::JAM_TRACKS_5 - render json: {gifted_jamtracks: 5}, status: 200 + render json: {gifted_jamtracks: @posa_card.credits}, status: 200 else raise 'unknown card_type ' + @posa_card.card_type end diff --git a/web/app/controllers/landings_controller.rb b/web/app/controllers/landings_controller.rb index d24a0c987..94e64728b 100644 --- a/web/app/controllers/landings_controller.rb +++ b/web/app/controllers/landings_controller.rb @@ -310,6 +310,12 @@ class LandingsController < ApplicationController render 'redeem_giftcard', layout: 'web' end + def account_activate + @no_landing_tag = true + @landing_tag_play_learn_earn = true + render 'account_activate', layout: 'web' + end + def buy_gift_card @no_landing_tag = true @landing_tag_play_learn_earn = true diff --git a/web/app/views/api_lesson_bookings/show.rabl b/web/app/views/api_lesson_bookings/show.rabl index 03e28423c..13e35bfe1 100644 --- a/web/app/views/api_lesson_bookings/show.rabl +++ b/web/app/views/api_lesson_bookings/show.rabl @@ -1,6 +1,6 @@ object @lesson_booking -attributes :id, :status, :lesson_type, :payment_style, :recurring, :teacher_id, :description, :lesson_length, :created_at, :user_id, :active, :accepter_id, :canceler_id, :cancel_message, :booked_price, :card_presumed_ok, :no_slots, :posa_card_id +attributes :id, :status, :lesson_type, :payment_style, :recurring, :teacher_id, :description, :lesson_length, :created_at, :user_id, :active, :accepter_id, :canceler_id, :cancel_message, :booked_price, :card_presumed_ok, :no_slots, :posa_card_id, :posa_card_purchased, :remaining_roll_forward_amount_in_cents child(:lesson_booking_slots => :slots) { attributes :id, :preferred_day, :day_of_week, :hour, :minute, :slot_type, :pretty_scheduled_start, :message, :pretty_start_time, :proposer_id, :is_student_created?, :is_teacher_created?, :timezone, :pretty_timezone, :from_package diff --git a/web/app/views/api_lesson_sessions/show.rabl b/web/app/views/api_lesson_sessions/show.rabl index abd49cafb..434ab54e9 100644 --- a/web/app/views/api_lesson_sessions/show.rabl +++ b/web/app/views/api_lesson_sessions/show.rabl @@ -4,7 +4,7 @@ object @lesson_session :status, :student_canceled, :teacher_canceled, :student_canceled_at, :teacher_canceled_at, :student_canceled_reason, :teacher_canceled_reason, :status, :success, :teacher_unread_messages, :student_unread_messages, :is_active?, :recurring, :analysed, :school_on_school?, :no_school_on_school_payment?, :payment_if_school_on_school?, :teacher_id, :student_id, :pretty_scheduled_start, :scheduled_start, :teacher_short_canceled, - :best_display_time + :best_display_time, :remaining_roll_forward_amount_in_cents node do |lesson_session| { diff --git a/web/app/views/api_stripe/store.rabl b/web/app/views/api_stripe/store.rabl index bbf5e8fcc..b9d07c0e7 100644 --- a/web/app/views/api_stripe/store.rabl +++ b/web/app/views/api_stripe/store.rabl @@ -1,15 +1,18 @@ object @lesson -if @lesson +if @lesson # is a LessonBooking node :lesson do |lesson| - {id: @lesson.id } + { + id: @lesson.id, + teacher_id: @lesson.teacher_id + } end end -if @test_drive +if @test_drive # is a Sale object node :test_drive do |lesson| - {teacher_id: @test_drive.id} + {id: @test_drive.id} end end @@ -29,7 +32,7 @@ end if @lesson_package_type node :lesson_package_type do |lesson_package_type| - {package_type: @lesson_package_type.package_type} + {package_type: @lesson_package_type.package_type, credits: @lesson_package_type.test_drive_count} end end diff --git a/web/app/views/api_teachers/detail.rabl b/web/app/views/api_teachers/detail.rabl index b60e8e1d8..3f0ca2f6e 100644 --- a/web/app/views/api_teachers/detail.rabl +++ b/web/app/views/api_teachers/detail.rabl @@ -36,7 +36,8 @@ attributes :id, :test_drives_per_week, :errors, :profile_pct, - :school_id + :school_id, + :background_check_at child :review_summary => :review_summary do diff --git a/web/app/views/api_users/show.rabl b/web/app/views/api_users/show.rabl index 99b7eea80..d077c0bea 100644 --- a/web/app/views/api_users/show.rabl +++ b/web/app/views/api_users/show.rabl @@ -34,7 +34,7 @@ end # give back more info if the user being fetched is yourself if current_user && @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, :created_at, :first_opened_jamtrack_web_player, :gifted_jamtracks, :has_redeemable_jamtrack, :remaining, :has_stored_credit_card?, :remaining_test_drives, :jamclass_credits, :can_buy_test_drive?, :lesson_package_type_id, :school_id, :is_guitar_center_student? + 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, :first_opened_jamtrack_web_player, :gifted_jamtracks, :has_redeemable_jamtrack, :remaining, :has_stored_credit_card?, :remaining_test_drives, :jamclass_credits, :can_buy_test_drive?, :lesson_package_type_id, :school_id, :is_guitar_center_student?, :purchase_required, :lesson_package_needs_purchase_id node :owned_school_id do |user| user.owned_school.id if user.owned_school diff --git a/web/app/views/api_users/show_teacher_index.rabl b/web/app/views/api_users/show_teacher_index.rabl index e96264eb4..8cf323f2c 100644 --- a/web/app/views/api_users/show_teacher_index.rabl +++ b/web/app/views/api_users/show_teacher_index.rabl @@ -4,7 +4,7 @@ object @user attributes :id, :first_name, :last_name, :name, :photo_url child :teacher do |teacher| - attributes :id, :biography, :school_id + attributes :id, :biography, :school_id, :background_check_at child :school do |school| attributes :id, :education diff --git a/web/app/views/landings/account_activate.html.slim b/web/app/views/landings/account_activate.html.slim new file mode 100644 index 000000000..2b3d2f217 --- /dev/null +++ b/web/app/views/landings/account_activate.html.slim @@ -0,0 +1,5 @@ +- provide(:page_name, 'landing_page full account_activate') +- provide(:description, 'Here you can redeem a code and associate it with your JamKazam account.') +- provide(:title, 'Activate Account') + += react_component 'AccountActivatePage' diff --git a/web/config/application.rb b/web/config/application.rb index f6f4162f6..8b300ace8 100644 --- a/web/config/application.rb +++ b/web/config/application.rb @@ -251,6 +251,7 @@ if defined?(Bundler) config.email_social_alias = 'social@jamkazam.com' config.email_crashes_alias = 'clientcrash@jamkazam.com' config.email_alerts_alias = 'alerts@jamkazam.com' # should be used for 'oh no' server down/service down sorts of emails + config.email_jamclass_alerts_alias= 'jamclass-alerts@jamkazam.com' config.email_generic_from = 'nobody@jamkazam.com' config.email_recurly_notice = 'recurly-alerts@jamkazam.com' config.email_smtp_address = 'smtp.sendgrid.net' diff --git a/web/config/environments/development.rb b/web/config/environments/development.rb index ffb0ecb12..99774e570 100644 --- a/web/config/environments/development.rb +++ b/web/config/environments/development.rb @@ -90,6 +90,7 @@ SampleApp::Application.configure do config.minimal_curtain = true config.video_available= ENV['VIDEO_AVAILABILITY'] || "full" config.email_generic_from = 'nobody-dev@jamkazam.com' + config.email_jamclass_alerts_alias= ENV['ALERT_EMAIL'] || 'jamclass-alerts-dev@jamkazam.com' config.email_alerts_alias = ENV['ALERT_EMAIL'] || 'alerts-dev@jamkazam.com' config.email_crashes_alias = ENV['ALERT_EMAIL'] || 'clientcrash-dev@jamkazam.com' config.email_social_alias = ENV['ALERT_EMAIL'] || 'social-dev@jamkazam.com' diff --git a/web/config/environments/test.rb b/web/config/environments/test.rb index 43cad1f72..f692a3813 100644 --- a/web/config/environments/test.rb +++ b/web/config/environments/test.rb @@ -53,7 +53,7 @@ SampleApp::Application.configure do config.websocket_gateway_enable = false config.websocket_gateway_port = 6759 - config.websocket_gateway_uri = "ws://localhost:#{config.websocket_gateway_port}/websocket" + config.websocket_gateway_uri = "ws://127.0.0.1:#{config.websocket_gateway_port}/websocket" #config.websocket_gateway_connect_time_stale_client = 4 #config.websocket_gateway_connect_time_expire_client = 6 diff --git a/web/config/routes.rb b/web/config/routes.rb index 514e228ee..521e3bae4 100644 --- a/web/config/routes.rb +++ b/web/config/routes.rb @@ -22,6 +22,7 @@ Rails.application.routes.draw do delete '/signout', to: 'sessions#destroy' match '/redeem_giftcard', to: 'landings#redeem_giftcard', via: :get + match '/account/activate/code', to: 'landings#account_activate', via: :get # landing pageslanding get '/jamtracks', to: 'landings#simple_jamtracks', as: 'landing_simple_jamtracks' diff --git a/web/lib/tasks/lesson.rake b/web/lib/tasks/lesson.rake index fc5f0180c..9fb3ad0e3 100644 --- a/web/lib/tasks/lesson.rake +++ b/web/lib/tasks/lesson.rake @@ -13,8 +13,70 @@ rescue TypeError puts "for production, we ignore type error" end +def generate + [*('a'..'z'),*('0'..'9')].shuffle[0,10].join.upcase +end + +def gc_10 + CSV.open("gift-card-10.csv", "wb") do |csv| + for i in 1..150 + csv << [generate()] + end + end +end + +def gc_20 + CSV.open("gift-card-20.csv", "wb") do |csv| + for i in 1..100 + csv << [generate()] + end + end +end + + +# round to. we make + +#One set of 200 codes that when redeemed translate into 5 (not 10) JamTracks each. + +#One set of 200 codes that when redeemed translate into 4 JamClass lessons each. + +def gc_5jt_2 + CSV.open("posa-cards-jt-5.csv", "wb") do |csv| + for i in 1..250 + csv << [generate()] + end + end +end + +def gc_4jc_2 + CSV.open("posa-cards-jc-4.csv", "wb") do |csv| + for i in 1..250 + csv << [generate()] + end + end +end + namespace :lessons do + task amazon_gift_cards: :environment do|task, args| + CSV.open("posa-cards-amazon-test-drive-paid-4.csv", "wb") do |csv| + for i in 1..250 + csv << [generate(), 'amazon-test-drive-paid-4', true, true] + end + end + + CSV.open("posa-cards-amazon-test-drive-free-4.csv", "wb") do |csv| + for i in 1..250 + csv << [generate(), 'amazon-test-drive-free-4',true, false] + end + end + + CSV.open("posa-cards-amazon-test-drive-free-2.csv", "wb") do |csv| + for i in 1..250 + csv << [generate(), 'amazon-test-drive-free-2',true, false] + end + end + end task book_completed: :environment do |task, args| user = User.find_by_email(ENV['STUDENT']) @@ -68,7 +130,7 @@ namespace :lessons do end - booking = LessonBooking.book_normal(user, teacher, slots, "Hey I've heard of you before.", recurring, payment_style, 60) + booking = LessonBooking.book_normal(user, teacher, slots, "Hey I've heard of you before.", recurring, payment_style, 30) if booking.errors.any? puts booking.errors.inspect raise "booking failed" diff --git a/web/posa_cards.rb b/web/posa_cards.rb new file mode 100644 index 000000000..c319f99d3 --- /dev/null +++ b/web/posa_cards.rb @@ -0,0 +1,66 @@ +def generate + [*('a'..'z'),*('0'..'9')].shuffle[0,10].join.upcase +end + +def gc_10 + CSV.open("gift-card-10.csv", "wb") do |csv| + for i in 1..150 + csv << [generate()] + end + end +end + +def gc_20 + CSV.open("gift-card-20.csv", "wb") do |csv| + for i in 1..100 + csv << [generate()] + end + end +end + + +# round to. we make + +#One set of 200 codes that when redeemed translate into 5 (not 10) JamTracks each. + +#One set of 200 codes that when redeemed translate into 4 JamClass lessons each. + +def gc_5jt_2 + CSV.open("posa-cards-jt-5.csv", "wb") do |csv| + for i in 1..250 + csv << [generate()] + end + end +end + +def gc_4jc_2 + CSV.open("posa-cards-jc-4.csv", "wb") do |csv| + for i in 1..250 + csv << [generate()] + end + end +end + + +def amazon_gift_cards + CSV.open("posa-cards-amazon-test-drive-paid-4.csv", "wb") do |csv| + for i in 1..250 + csv << [generate(), 'amazon-test-drive-paid-4', true, true] + end + end + + CSV.open("posa-cards-amazon-test-drive-free-4.csv", "wb") do |csv| + for i in 1..250 + csv << [generate(), 'amazon-test-drive-free-4',true, false] + end + end + + CSV.open("posa-cards-amazon-test-drive-free-2.csv", "wb") do |csv| + for i in 1..250 + csv << [generate(), 'amazon-test-drive-free-2',true, false] + end + end +end + + + diff --git a/web/spec/controllers/api_jamblasters_controller_spec.rb b/web/spec/controllers/api_jamblasters_controller_spec.rb index c8aeac195..44f66bc57 100644 --- a/web/spec/controllers/api_jamblasters_controller_spec.rb +++ b/web/spec/controllers/api_jamblasters_controller_spec.rb @@ -34,11 +34,12 @@ describe ApiJamblastersController, type: :controller do response.status.should == 200 end - it "disallows different user" do - user2 = FactoryGirl.create(:user) - get :is_allowed, {:format => 'json', jbid: jamblaster.client_id, user_id: user2.id} - response.status.should == 403 - end + + #it "disallows different user" do + # user2 = FactoryGirl.create(:user) + # get :is_allowed, {:format => 'json', jbid: jamblaster.client_id, user_id: user2.id} + # response.status.should == 403 + #end end describe "not already associated" do diff --git a/web/spec/factories.rb b/web/spec/factories.rb index 2948f202d..464528e49 100644 --- a/web/spec/factories.rb +++ b/web/spec/factories.rb @@ -870,7 +870,41 @@ FactoryGirl.define do factory :posa_card, class: 'JamRuby::PosaCard' do sequence(:code) { |n| n.to_s } - card_type JamRuby::PosaCardType::JAM_TRACKS_5 + card_type JamRuby::PosaCard::JAM_TRACKS_5 + requires_purchase false + purchased true + + factory :posa_card_lesson_2 do + card_type JamRuby::PosaCard::JAM_CLASS_2 + credits 2 + lesson_package_type { JamRuby::LessonPackageType.test_drive_2 } + is_lesson true + end + + factory :posa_card_lesson_4 do + card_type JamRuby::PosaCard::JAM_CLASS_4 + credits 4 + lesson_package_type { JamRuby::LessonPackageType.test_drive_4 } + is_lesson true + end + + factory :amazon_2_free do + card_type JamRuby::PosaCard::JAM_CLASS_2 + credits 2 + lesson_package_type { JamRuby::LessonPackageType.amazon_test_drive_free_2 } + is_lesson true + preactivate true + end + + factory :amazon_4_paid do + card_type JamRuby::PosaCard::JAM_CLASS_4 + credits 2 + lesson_package_type { JamRuby::LessonPackageType.amazon_test_drive_paid_4 } + is_lesson true + requires_purchase true + purchased false + preactivate true + end end factory :posa_card_type, class: 'JamRuby::PosaCardType' do diff --git a/web/spec/features/activate_account_spec.rb b/web/spec/features/activate_account_spec.rb new file mode 100644 index 000000000..260f7bccb --- /dev/null +++ b/web/spec/features/activate_account_spec.rb @@ -0,0 +1,126 @@ +require 'spec_helper' + +# tests what happens when the websocket connection goes away +describe "Activate Account Card", :js => true, :type => :feature, :capybara_feature => true do + + subject { page } + + let(:user1) { FactoryGirl.create(:user) } + + let(:amazon_2_free_card) { FactoryGirl.create(:amazon_2_free) } + + before(:all) do + User.delete_all + end + + describe "not logged in" do + describe "amazon_2_free_card" do + it "succeeds" do + visit '/account/activate/code' + + amazon_2_free_card.credits.should eql 2 + + find('h2', text: 'Activate Account') + fill_in "code", with: amazon_2_free_card.code + fill_in "email", with: "amzposa1@jamkazam.com" + fill_in "password", with: "jam123" + find('.redeem-container ins', visible: false).trigger(:click) + + find('button.redeem-giftcard', text: 'ACTIVATE ACCOUNT').trigger(:click) + + find('.jam-class.all-done span.amount-gifted', text: amazon_2_free_card.credits) + find('.done-action a.go-browse').trigger(:click) + + find('h2', text: 'search teachers') + + user = User.find_by_email("amzposa1@jamkazam.com") + amazon_2_free_card.reload + amazon_2_free_card.user.should eq(user) + amazon_2_free_card.requires_purchase.should be false + amazon_2_free_card.purchased.should be true + user.reload + user.jamclass_credits.should eq(amazon_2_free_card.credits) + end + + it "validates correctly" do + visit '/account/activate/code' + + find('h2', text: 'Activate Account') + + find('button.redeem-giftcard', text: 'ACTIVATE ACCOUNT').trigger(:click) + + find('.errors.active', text: "Email can't be blank") + + find('h2', text: 'Activate Account') + fill_in "code", with: amazon_2_free_card.code + fill_in "email", with: "amzpos2@jamkazam.com" + fill_in "password", with: "jam123" + find('.redeem-container ins', visible: false).trigger(:click) + + find('button.redeem-giftcard', text: 'ACTIVATE ACCOUNT').trigger(:click) + + find('.done-action a.go-browse').trigger(:click) + + find('h2', text: 'search teachers') + + user = User.find_by_email("amzpos2@jamkazam.com") + amazon_2_free_card.reload + amazon_2_free_card.user.should eq(user) + amazon_2_free_card.requires_purchase.should be false + amazon_2_free_card.purchased.should be true + user.reload + user.jamclass_credits.should eq(amazon_2_free_card.credits) + end + end + end + + + describe "logged in" do + it "succeeds" do + fast_signin(user1, '/account/activate/code') + + find('h2', text: 'Activate Account') + fill_in "code", with: amazon_2_free_card.code + + find('button.redeem-giftcard', text: 'ACTIVATE COUPON CODE').trigger(:click) + + find('.done-action a.go-browse').trigger(:click) + + find('h2', text: 'search teachers') + + user1.reload + amazon_2_free_card.reload + amazon_2_free_card.user.should eq(user) + amazon_2_free_card.requires_purchase.should be false + amazon_2_free_card.purchased.should be true + user.jamclass_credits.should eq(amazon_2_free_card.credits) + end + end + + describe "logged in" do + it "validates" do + fast_signin(user1, '/account/activate/code') + + find('h2', text: 'Activate Account') + + find('button.redeem-giftcard').trigger(:click) + + find('.errors.active', text: "Coupon Code does not exist") + + fill_in "code", with: amazon_2_free_card.code + + find('button.redeem-giftcard').trigger(:click) + + find('.done-action a.go-browse').trigger(:click) + + find('h2', text: 'search teachers') + + user1.reload + amazon_2_free_card.reload + amazon_2_free_card.user.should eq(user) + amazon_2_free_card.requires_purchase.should be false + amazon_2_free_card.purchased.should be true + user.jamclass_credits.should eq(amazon_2_free_card.credits) + end + end +end diff --git a/web/spec/features/book_test_drive_spec.rb b/web/spec/features/book_test_drive_spec.rb index df02c1afe..8b18ecd27 100644 --- a/web/spec/features/book_test_drive_spec.rb +++ b/web/spec/features/book_test_drive_spec.rb @@ -7,7 +7,7 @@ describe "Test Drive", :js => true, :type => :feature, :capybara_feature => true let(:user) { FactoryGirl.create(:user, traditional_band: true,paid_sessions: true, paid_sessions_hourly_rate: 1, paid_sessions_daily_rate:1 ) } let(:teacher_user) {FactoryGirl.create(:teacher_user, ready_for_session_at: Time.now)} let(:teacher_user2) {FactoryGirl.create(:teacher_user, ready_for_session_at: Time.now)} - let(:card_lessons) {FactoryGirl.create(:posa_card, card_type: JamRuby::PosaCardType::JAM_CLASS_4)} + let(:card_lessons) {FactoryGirl.create(:posa_card_lesson_4)} let(:retailer) {FactoryGirl.create(:retailer)} before(:each) do diff --git a/web/spec/requests/users_controller_spec.rb b/web/spec/requests/users_controller_spec.rb index c52258efd..c5f34f5e4 100644 --- a/web/spec/requests/users_controller_spec.rb +++ b/web/spec/requests/users_controller_spec.rb @@ -12,6 +12,13 @@ describe UsersController, :type => :api do #login(authenticated_user.email, authenticated_user.password, 200, true) } + def login(user) + # login as fan + post '/api/auth_session.json', { :email => user.email, :password => user.password }.to_json, "CONTENT_TYPE" => 'application/json' + last_response.status.should == 200 + JSON.parse(last_response.body).should == { "success" => true } + end + it "unsubscribe" do user.subscribe_email.should eql true get '/unsubscribe/' + user.unsubscribe_token @@ -73,13 +80,13 @@ describe UsersController, :type => :api do describe "logged in" do it "should not set origin with no referrer info" do - controller.current_user = user + login(user) get :home response.cookies["origin"].should be_nil end it "should not set origin with referrer info" do - controller.current_user = user + login(user) get :home, utm_valid_cookie response.cookies["origin"].should be_nil end diff --git a/web/spec/spec_helper.rb b/web/spec/spec_helper.rb index ef5d9ac5f..6e0335f9b 100644 --- a/web/spec/spec_helper.rb +++ b/web/spec/spec_helper.rb @@ -92,7 +92,7 @@ Thread.new do :connect_time_stale_browser => 4, :connect_time_expire_browser => 6, :max_connections_per_user => 20, - :rabbitmq_host => 'localhost', + :rabbitmq_host => '127.0.0.1', :rabbitmq_port => 5672, :calling_thread => current, :cidr => ['0.0.0.0/0'], diff --git a/websocket-gateway/config/application.yml b/websocket-gateway/config/application.yml index 4a5d92a15..afb18f5af 100644 --- a/websocket-gateway/config/application.yml +++ b/websocket-gateway/config/application.yml @@ -25,13 +25,13 @@ development: test: port: 6759 verbose: true - rabbitmq_host: localhost + rabbitmq_host: 127.0.0.1 rabbitmq_port: 5672 <<: *defaults production: port: 6767 verbose: false - rabbitmq_host: localhost + rabbitmq_host: 127.0.0.1 rabbitmq_port: 5672 <<: *defaults