diff --git a/admin/Gemfile b/admin/Gemfile index f12413723..595d94904 100644 --- a/admin/Gemfile +++ b/admin/Gemfile @@ -108,7 +108,7 @@ end group :development, :test do gem 'capybara' - gem 'rspec-rails', '2.14.2' + gem 'rspec-rails' #, '2.14.2' gem 'jasmine', '1.3.1' gem 'execjs', '1.4.0' #gem 'therubyracer' #, '0.11.0beta8' diff --git a/admin/Gemfile.lock b/admin/Gemfile.lock index ec7d8fc45..d029ef2ce 100644 --- a/admin/Gemfile.lock +++ b/admin/Gemfile.lock @@ -92,7 +92,7 @@ GEM aws-sdk-v1 (1.67.0) json (~> 1.4) nokogiri (~> 1) - backports (3.11.0) + backports (3.11.1) bcrypt (3.1.11) bcrypt-ruby (3.0.1) binding_of_caller (0.8.0) @@ -100,7 +100,7 @@ GEM bootstrap-sass (2.0.4.0) bootstrap-will_paginate (0.0.6) will_paginate - bugsnag (6.6.1) + bugsnag (6.6.3) concurrent-ruby (~> 1.0) builder (3.2.3) cabin (0.9.0) @@ -147,7 +147,7 @@ GEM crass (1.0.3) database_cleaner (1.6.2) debug_inspector (0.0.3) - devise (4.4.0) + devise (4.4.1) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 4.1.0, < 5.2) @@ -160,7 +160,7 @@ GEM email_validator (1.6.0) activemodel erubis (2.7.0) - et-orbi (1.0.8) + et-orbi (1.0.9) tzinfo eventmachine (1.2.3) excon (0.60.0) @@ -173,7 +173,7 @@ GEM railties (>= 3.0.0) faker (1.3.0) i18n (~> 0.5) - faraday (0.13.1) + faraday (0.14.0) multipart-post (>= 1.2, < 3) ffi (1.9.18) fission (0.5.0) @@ -314,10 +314,10 @@ GEM domain_name (~> 0.5) httparty (0.15.6) multi_xml (>= 0.5.2) - i18n (0.9.1) + i18n (0.9.3) concurrent-ruby (~> 1.0) inflecto (0.0.2) - influxdb (0.5.2) + influxdb (0.5.3) influxdb-rails (0.4.3) influxdb (~> 0.5.0) railties (> 3) @@ -374,7 +374,7 @@ GEM mimemagic (0.3.2) mini_mime (1.0.0) mini_portile2 (2.3.0) - minitest (5.11.1) + minitest (5.11.2) mono_logger (1.1.0) multi_json (1.13.1) multi_xml (0.6.0) @@ -404,7 +404,7 @@ GEM capybara (~> 2.1) cliver (~> 0.3.1) websocket-driver (>= 0.2.0) - polyamorous (1.3.2) + polyamorous (1.3.3) activerecord (>= 3.0) postgres-copy (0.6.0) activerecord (>= 3.0.0) @@ -428,7 +428,7 @@ GEM binding_of_caller (>= 0.7) pry (>= 0.9.11) public_suffix (3.0.1) - puma (3.11.0) + puma (3.11.2) rack (1.6.8) rack-protection (1.5.3) rack @@ -464,16 +464,16 @@ GEM thor (>= 0.18.1, < 2.0) raindrops (0.19.0) rake (12.3.0) - ransack (1.8.4) + ransack (1.8.6) actionpack (>= 3.0) activerecord (>= 3.0) activesupport (>= 3.0) i18n - polyamorous (~> 1.3) + polyamorous (~> 1.3.2) rb-fsevent (0.10.2) rb-inotify (0.9.10) ffi (>= 0.5.0, < 2) - recurly (2.12.0) + recurly (2.12.1) redis (4.0.1) redis-namespace (1.6.0) redis (>= 3.0.4) @@ -507,22 +507,27 @@ GEM http-cookie (>= 1.0.2, < 2.0) mime-types (>= 1.16, < 4.0) netrc (~> 0.8) - rspec (2.14.1) - rspec-core (~> 2.14.0) - rspec-expectations (~> 2.14.0) - rspec-mocks (~> 2.14.0) - rspec-core (2.14.8) - rspec-expectations (2.14.5) - diff-lcs (>= 1.1.3, < 2.0) - rspec-mocks (2.14.6) - rspec-rails (2.14.2) + rspec (3.7.0) + rspec-core (~> 3.7.0) + rspec-expectations (~> 3.7.0) + rspec-mocks (~> 3.7.0) + rspec-core (3.7.1) + rspec-support (~> 3.7.0) + rspec-expectations (3.7.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.7.0) + rspec-mocks (3.7.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.7.0) + rspec-rails (3.7.2) actionpack (>= 3.0) - activemodel (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) - rspec-core (~> 2.14.0) - rspec-expectations (~> 2.14.0) - rspec-mocks (~> 2.14.0) + rspec-core (~> 3.7.0) + rspec-expectations (~> 3.7.0) + rspec-mocks (~> 3.7.0) + rspec-support (~> 3.7.0) + rspec-support (3.7.0) ruby-protocol-buffers (1.2.2) ruby-xz (0.2.3) ffi (~> 1.9) @@ -589,7 +594,7 @@ GEM tilt (2.0.8) tzinfo (1.2.4) thread_safe (~> 0.1) - uglifier (4.1.3) + uglifier (4.1.4) execjs (>= 0.3.0, < 3) unf (0.1.3) unf_ext @@ -679,7 +684,7 @@ DEPENDENCIES resque-retry resque_mailer rest-client - rspec-rails (= 2.14.2) + rspec-rails ruby-protocol-buffers (= 1.2.2) rubyzip sanitize diff --git a/admin/app/admin/dashboard.rb b/admin/app/admin/dashboard.rb index a22643621..51903b216 100644 --- a/admin/app/admin/dashboard.rb +++ b/admin/app/admin/dashboard.rb @@ -5,11 +5,14 @@ ActiveAdmin.register_page "Dashboard" do content :title => proc{ I18n.t("active_admin.dashboard") } do div :class => "blank_slate_container", :id => "dashboard_default_message" do span :class => "blank_slate" do - span "JamKazam Data Administration Portal" + span "JamKazam Administration Portal" small ul do - li "Admin users are users with the admin boolean set to true" - li "Invite JamKazam users using the 'Users > Invite' menu in header" - li "Admin users are created/deleted when toggling the 'admin' flag for JamKazam users" + li link_to "Users", admin_users_path + li link_to "Teachers", admin_teachers_path + li link_to "Onboarding Management", admin_currently_onboardings_path + li link_to "Lesson Sessions", admin_lesson_sessions_path + li link_to "Slow Lesson Responses", admin_slow_responses_path + end end end diff --git a/admin/app/admin/jam_ruby_users.rb b/admin/app/admin/jam_ruby_users.rb index 2c4029549..cce181faf 100644 --- a/admin/app/admin/jam_ruby_users.rb +++ b/admin/app/admin/jam_ruby_users.rb @@ -12,6 +12,8 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do filter :created_at filter :updated_at + includes :purchased_jam_tracks, :jam_track_rights => :jam_track, :taken_lessons => :music_session, :taught_lessons => :music_session + form :partial => "form" show do |user| @@ -79,7 +81,9 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do else end end - row "Signup" do user.created_at.to_date end + row "Signup" do + user.created_at.to_date + end row "Assigned", :onboarder_assigned_at row "Email 1", :onboarding_email_1_sent_at row "Email 2", :onboarding_email_2_sent_at @@ -97,6 +101,14 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do end end + + panel "Teacher Setting" do + attributes_table do + row :is_searchable + end + end if user.teacher + + panel "Lessons" do attributes_table do row "Taken Lessons" do @@ -154,6 +166,24 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do end + panel "JamTracks" do + div do + link_to "Give JamTrack", "../jam_track_rights/new" + end + + attributes_table do + row "Purchased JamTracks" do + table_for user.purchased_jam_tracks.unscope(:order).order('original_artist asc', 'name asc') do + column "Artist", :original_artist + column "Name", :name + column "Can Download", :can_download, as: :boolean, hint: 'Can download is the 2.99 value (have download rights)' + column "Version", :version + column "ID", :id + end + end + end + end + active_admin_comments end @@ -174,22 +204,14 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do link_to user.email, resource_path(user) end column :admin - column :updated_at column :created_at column :musician do |user| user.musician? ? true : false end column :city column :state - column :country column :first_name column :last_name - column :birth_date - column :gender - column :email_confirmed - column :photo_url - column :session_settings - column :can_invite end controller do diff --git a/admin/app/admin/jam_track_right.rb b/admin/app/admin/jam_track_right.rb index 0ea648dcb..6892b6aaf 100644 --- a/admin/app/admin/jam_track_right.rb +++ b/admin/app/admin/jam_track_right.rb @@ -49,6 +49,7 @@ ActiveAdmin.register JamRuby::JamTrackRight, :as => 'JamTrackRights' do f.inputs 'New Jam Track Right' do f.input :jam_track, :required=>true, collection: JamTrack.all, include_blank: false f.input :user, :required=>true, collection: User.all, include_blank: false + f.input :can_download, :required => true, as: :boolean end f.actions end diff --git a/admin/app/admin/slow_responses.rb b/admin/app/admin/slow_responses.rb index 46bb3f919..32f3f3045 100644 --- a/admin/app/admin/slow_responses.rb +++ b/admin/app/admin/slow_responses.rb @@ -6,45 +6,101 @@ ActiveAdmin.register JamRuby::LessonSession, :as => 'SlowResponses' do config.batch_actions = false config.per_page = 100 config.paginate = true - config.filters = false + config.filters = true - scope("Slow Responses", default: true) { |scope| scope.unscoped.slow_responses } - scope("Least Time Left") { |scope| scope.unscoped.least_time_left } + filter :intervened_at_null, label: 'Not Yet Intervened', as: :boolean + + scope("72 hours since last request/counter", default: true) { |scope| scope.slow_responses } + + member_action :cancel_lesson, :method => :get do + result = resource.cancel_by_admin + + if result.errors.any? + redirect_to :back, notice: resource.errors.inspect + else + redirect_to :back, notice: 'Canceled lesson' + end + end + + member_action :intervened, :method => :get do + resource.intervened + redirect_to :back + end index do - column "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}" + column "Not Responded" do |lesson_session| + div do + if lesson_session.student_last_proposed? + "Teacher" + else + "Student" + end + end + div do + late_responder = lesson_session.late_responder + span do + link_to "#{late_responder.name}", late_responder.admin_url + end + end + div do + lesson_session.late_responder.email end end - column "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}" + column "Proposer" do |lesson_session| + div do + if lesson_session.student_last_proposed? + "Student" + else + "Teacher" + end + end + div do + last_proposer = lesson_session.last_proposer + span do + link_to "#{last_proposer.name}", last_proposer.admin_url + end + end + div do + lesson_session.last_proposer.email end end - column "Type" do |lesson_session| - link_to lesson_session.display_type + column "Lesson Type" do |lesson_session| + lesson_session.display_type end - column "Start Time" do |lesson_session| + column "Proposed Start Time" do |lesson_session| span do if lesson_session.music_session.nil? raise "Lessonsesison with no id #{lesson_session.id}" else - lesson_session.music_session.pretty_scheduled_start(true) + link_to lesson_session.music_session.pretty_scheduled_start(true), lesson_session.admin_url + end end end - column "Last student comms date" do |lesson_session| - lesson_session.last_student_comm_date - end column "Days with no response" do |lesson_session| - "#{lesson_session.days_no_response} days" + if lesson_session.last_response_time.nil? + 'N/A' + else + "#{((Time.now - lesson_session.last_response_time) / 24 / 3600).floor} days" + end end + column "Num Reqs/Counters" do |lesson_session| + ChatMessage.unscoped.where(lesson_session_id: lesson_session.id).where('purpose = ? OR purpose = ?', "Lesson Requested", "New Time Proposed").count(:purpose) + end + column "Intervene" do |lesson_session| + span do + if lesson_session.intervened_at + lesson_session.intervened_at.to_date + else + link_to("intervened", intervened_admin_slow_response_path(lesson_session.id), {confirm: "Mark Lesson as 'Intervened' (i.e., email sent to by hand)?"}) + end - - + end + end + column "Cancel Lesson" do |lesson_session| + span do + link_to("cancel", cancel_lesson_admin_slow_response_path(lesson_session.id), {confirm: "Cancel Lesson?"}) + end + end end - end \ No newline at end of file diff --git a/admin/app/admin/teachers.rb b/admin/app/admin/teachers.rb index c79cd5bfb..7976a7cd3 100644 --- a/admin/app/admin/teachers.rb +++ b/admin/app/admin/teachers.rb @@ -18,7 +18,7 @@ ActiveAdmin.register JamRuby::Teacher, :as => 'Teachers' do end filter :teacher_full_name_or_user_email_cont, label: 'Name', as: :string - filter :user_phantom, label: 'Phantom', as: :boolean, selected: 'false' + filter :user_phantom, label: 'Phantom ', as: :boolean, selected: 'false' #filter :by_search_user_name, label: "Name", as: :string diff --git a/db/manifest b/db/manifest index 61df1be7d..19a9059d2 100755 --- a/db/manifest +++ b/db/manifest @@ -382,4 +382,5 @@ amazon_signup.sql age_out_sessions.sql alter_crash_dumps.sql onboarding.sql -better_lesson_notices.sql \ No newline at end of file +better_lesson_notices.sql +teacher_search_control.sql \ No newline at end of file diff --git a/db/up/teacher_search_control.sql b/db/up/teacher_search_control.sql new file mode 100644 index 000000000..60a017ac0 --- /dev/null +++ b/db/up/teacher_search_control.sql @@ -0,0 +1,4 @@ +ALTER TABLE teachers ADD COLUMN is_searchable BOOLEAN NOT NULL DEFAULT true; +ALTER TABLE lesson_sessions ADD COLUMN canceled_by_admin TIMESTAMP without time zone; +ALTER TABLE lesson_bookings ADD COLUMN canceled_by_admin TIMESTAMP without time zone; +ALTER TABLE lesson_sessions ADD COLUMN intervened_at TIMESTAMP without time zone; \ No newline at end of file diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_canceled.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_canceled.html.erb index 7151dbcfb..a0420f3ef 100644 --- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_canceled.html.erb +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_canceled.html.erb @@ -1,6 +1,9 @@ <% provide(:title, @subject) %> -<% provide(:photo_url, @lesson_booking.canceler.resolved_photo_url) %> - +<% if @lesson_booking.canceler %> + <% provide(:photo_url, @lesson_booking.canceler.resolved_photo_url) %> +<% else %> + <% provide(:photo_url, "#{APP_CONFIG.external_root_url}/assets/shared/avatar_generic.png") %> +<% end %> <% content_for :note do %>
<% if @lesson_booking.recurring %> diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_declined.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_declined.html.erb index 410621edb..b394a33cc 100644 --- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_declined.html.erb +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/student_lesson_booking_declined.html.erb @@ -4,14 +4,27 @@ <% content_for :note do %>
- This teacher has declined your lesson request.
+ <% if @lesson_booking.canceled_by_admin %>
+ This lesson was canceled by a JamKazam administrator.
+ <% else %>
+ This teacher has declined your lesson request.
+ <% end %>
<% if @message.present? %>
-
<%= @teacher.name %> says:
+ <% if @lesson_booking.canceled_by_admin %>
+
System says:
+ <% else %>
+
<%= @teacher.name %> says:
+ <% end %>
<%= @message %>
<% end %>
-
Click the button below to view the teacher's response.
@@ -10,7 +14,11 @@
<%= @session_date %>
<% if @message.present? %>
-
<%= @lesson_session.canceler.name %> says:
+ <% if @lesson_session.canceled_by_admin %>
+
System says:
+ <% else %>
+
<%= @lesson_session.canceler.name %> says:
+ <% end %>
<%= @message %>
<% end %>
diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_booking_canceled.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_booking_canceled.html.erb
index 8de563ccf..a5fd6749a 100644
--- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_booking_canceled.html.erb
+++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_booking_canceled.html.erb
@@ -1,5 +1,9 @@
<% provide(:title, @subject) %>
-<% provide(:photo_url, @lesson_booking.canceler.resolved_photo_url) %>
+<% if @lesson_booking.canceler %>
+ <% provide(:photo_url, @lesson_booking.canceler.resolved_photo_url) %>
+<% else %>
+ <% provide(:photo_url, "#{APP_CONFIG.external_root_url}/assets/shared/avatar_generic.png") %>
+<% end %>
<% content_for :note do %>
@@ -16,7 +20,12 @@
<% end %>
<% if @message.present? %>
-
<%= @lesson_booking.canceler.name %> says:
+ <% if @lesson_booking.canceled_by_admin %>
+
System says:
+ <% else %>
+
<%= @lesson_booking.canceler.name %> says:
+ <% end %>
+
<%= @message %>
<% end %>
diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_canceled.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_canceled.html.erb
index 4a60fe695..a96d48b59 100644
--- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_canceled.html.erb
+++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/teacher_lesson_canceled.html.erb
@@ -1,5 +1,9 @@
<% provide(:title, @subject) %>
-<% provide(:photo_url, @lesson_session.canceler.resolved_photo_url) %>
+<% if @lesson_booking.canceler %>
+ <% provide(:photo_url, @lesson_session.canceler.resolved_photo_url) %>
+<% else %>
+ <% provide(:photo_url, "#{APP_CONFIG.external_root_url}/assets/shared/avatar_generic.png") %>
+<% end %>
<% content_for :note do %>
@@ -11,7 +15,11 @@
<%= @session_date %>
<% if @message.present? %>
-
<%= @lesson_session.canceler.name %> says:
+ <% if @lesson_session.canceled_by_admin %>
+
System says:
+ <% else %>
+
<%= @lesson_session.canceler.name %> says:
+ <% end %>
<%= @message %>
<% end %>
diff --git a/ruby/lib/jam_ruby/models/jam_track_right.rb b/ruby/lib/jam_ruby/models/jam_track_right.rb
index b9af3eaf8..e02399663 100644
--- a/ruby/lib/jam_ruby/models/jam_track_right.rb
+++ b/ruby/lib/jam_ruby/models/jam_track_right.rb
@@ -7,7 +7,7 @@ module JamRuby
@@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 :user_id, :jam_track_id, :can_download, 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 :jam_track, class_name: "JamRuby::JamTrack"
@@ -38,6 +38,8 @@ module JamRuby
key = rsa_key.to_pem()
self.private_key_44 = key
self.private_key_48 = key
+
+ self.version = jam_track.version
end
def after_save
# try to catch major transitions:
diff --git a/ruby/lib/jam_ruby/models/lesson_booking.rb b/ruby/lib/jam_ruby/models/lesson_booking.rb
index 2280ad086..ddd30c2b1 100644
--- a/ruby/lib/jam_ruby/models/lesson_booking.rb
+++ b/ruby/lib/jam_ruby/models/lesson_booking.rb
@@ -741,14 +741,16 @@ module JamRuby
self
end
- def cancel_tracking(canceler, message)
+ def cancel_tracking(canceler, message, canceled_by_admin = false)
canceled_by_student = canceler == student
self.status = STATUS_CANCELED
self.cancel_message = message
- self.canceler = canceler
+ self.canceler = canceler if !canceled_by_admin
self.canceling = true
- if canceled_by_student
+ if canceled_by_admin
+ self.canceled_by_admin = Time.now
+ elsif canceled_by_student
self.student_canceled = true
self.student_canceled_at = Time.now
self.student_canceled_reason = message
@@ -759,16 +761,16 @@ module JamRuby
end
end
- def cancel(canceler, other, message)
+ def cancel(canceler, other, message, canceled_by_admin = false)
- cancel_tracking(canceler, message)
+ cancel_tracking(canceler, message, canceled_by_admin)
self.active = false
success = save
if success
lesson_sessions.upcoming.each do |lesson_session|
lesson_session = LessonSession.find(lesson_session.id) # because .upcoming creates ReadOnly records
- lesson_session.cancel_lesson(canceler, message)
+ lesson_session.cancel_lesson(canceler, message, canceled_by_admin)
if !lesson_session.save
return lesson_session
end
@@ -781,7 +783,12 @@ module JamRuby
UserMailer.teacher_lesson_booking_canceled(self, message).deliver_now
purpose = "Lesson Canceled"
else
- if canceler == student
+ if canceled_by_admin
+ # meh. no two way comm here. just bail
+ #Notification.send_lesson_message('canceled', next_lesson, true)
+ UserMailer.student_lesson_booking_declined(self, message).deliver_now
+ UserMailer.teacher_lesson_booking_canceled(self, message).deliver_now
+ elsif canceler == student
# if it's the first time acceptance student canceling, we call it a 'cancel'
Notification.send_lesson_message('canceled', next_lesson, false)
UserMailer.teacher_lesson_booking_canceled(self, message).deliver_now
@@ -795,7 +802,9 @@ module JamRuby
end
message = '' if message.nil?
- msg = ChatMessage.create(canceler, nil, message, ChatMessage::CHANNEL_LESSON, nil, other, next_lesson, purpose)
+ if !canceled_by_admin
+ msg = ChatMessage.create(canceler, nil, message, ChatMessage::CHANNEL_LESSON, nil, other, next_lesson, purpose)
+ end
else
end
diff --git a/ruby/lib/jam_ruby/models/lesson_session.rb b/ruby/lib/jam_ruby/models/lesson_session.rb
index 2fa288174..3251695d8 100644
--- a/ruby/lib/jam_ruby/models/lesson_session.rb
+++ b/ruby/lib/jam_ruby/models/lesson_session.rb
@@ -79,11 +79,8 @@ module JamRuby
scope :past_cancel_window, -> { joins(:music_session).where('music_sessions.scheduled_start > ?', 24.hours.from_now) }
# show all requested/countered sessions where the student was the last to communicate
scope :slow_responses, -> { joins(:lesson_booking).where('lesson_sessions.status = ? OR lesson_sessions.status = ?', LessonSession::STATUS_REQUESTED, LessonSession::STATUS_COUNTERED)
- .where('lesson_sessions.counterer_id IS NULL OR lesson_sessions.user_id = lesson_sessions.counterer_id')
+ .where("(? - (COALESCE(lesson_sessions.countered_at, lesson_bookings.sent_notices_at))) > INTERVAL '72 hours'", Time.now)
.order('(COALESCE(lesson_sessions.countered_at, lesson_bookings.sent_notices_at)) ASC') }
- scope :least_time_left, -> { joins(:lesson_booking, :music_session).where('lesson_sessions.status = ? OR lesson_sessions.status = ?', LessonSession::STATUS_REQUESTED, LessonSession::STATUS_COUNTERED)
- .where('lesson_sessions.counterer_id IS NULL OR lesson_sessions.user_id = lesson_sessions.counterer_id')
- .order('music_sessions.scheduled_start DESC') }
def create_charge
if payment_if_school_on_school? && !is_test_drive? && !is_monthly_payment?
@@ -222,6 +219,22 @@ module JamRuby
counterer_id.nil? || counterer_id == student_id
end
+ def late_responder
+ if student_last_proposed?
+ teacher
+ else
+ student
+ end
+ end
+
+ def last_proposer
+ if student_last_proposed?
+ student
+ else
+ teacher
+ end
+ end
+
def lesson_is_free?
lesson_booking.booked_price == 0.00
end
@@ -999,15 +1012,17 @@ module JamRuby
response
end
- def cancel_lesson(canceler, message)
+ def cancel_lesson(canceler, message, canceled_by_admin = false)
canceled_by_student = canceler == student
self.status = STATUS_CANCELED
self.cancel_message = message
- self.canceler = canceler
+ self.canceler = canceler if !canceled_by_admin
self.canceling = true
- if canceled_by_student
+ if canceled_by_admin
+
+ elsif canceled_by_student
self.student_canceled = true
self.student_canceled_at = Time.now
self.student_canceled_reason = message
@@ -1059,6 +1074,10 @@ module JamRuby
other = canceled_by_student ? teacher : student
message = params[:message]
message = '' if message.nil?
+ if params[:canceled_by_admin]
+ self.canceled_by_admin = Time.now
+ end
+
if lesson_booking.recurring
update_all = params[:update_all]
@@ -1071,7 +1090,7 @@ module JamRuby
end
if update_all
- response = lesson_booking.cancel(canceler, other, message)
+ response = lesson_booking.cancel(canceler, other, message, params[:canceled_by_admin])
if response.errors.any?
raise ActiveRecord::Rollback
end
@@ -1081,13 +1100,20 @@ module JamRuby
raise ActiveRecord::Rollback
end
else
- cancel_lesson(canceler, message)
+ cancel_lesson(canceler, message, params[:canceled_by_admin])
if !save
response = self
raise ActiveRecord::Rollback
end
- msg = ChatMessage.create(canceler, nil, message, ChatMessage::CHANNEL_LESSON, nil, other, self, "Lesson Canceled")
+ if canceled_by_admin
+ msg = ChatMessage.create(student, nil, message, ChatMessage::CHANNEL_LESSON, nil, teacher, self, "Lesson Canceled")
+ msg = ChatMessage.create(teacher, nil, message, ChatMessage::CHANNEL_LESSON, nil, student, self, "Lesson Canceled")
+ else
+ msg = ChatMessage.create(canceler, nil, message, ChatMessage::CHANNEL_LESSON, nil, other, self, "Lesson Canceled")
+ end
+
+
Notification.send_lesson_message('canceled', self, false)
Notification.send_lesson_message('canceled', self, true)
UserMailer.student_lesson_canceled(self, message).deliver_now
@@ -1108,8 +1134,6 @@ module JamRuby
else
'TBD'
end
-
-
end
def timed_description
if is_test_drive?
@@ -1123,6 +1147,20 @@ module JamRuby
end
end
+ def cancel_by_admin
+ self.cancel({
+ canceler: nil,
+ canceled_by_admin: true,
+ message: 'Canceled by JamKazam administrator',
+ update_all: false
+ })
+ end
+
+ def intervened
+ self.intervened_at = Time.now
+ self.save
+ end
+
def display_type
if is_test_drive?
'TestDrive'
@@ -1137,15 +1175,8 @@ module JamRuby
counterer_id == user_id ? countered_at : sent_notices_at
end
- def days_no_response
- date = last_student_comm_date
- if date.nil?
- '?'
- else
- (Time.now - last_student_comm_date) / (60 * 60 * 24)
- end
-
-
+ def last_response_time
+ [countered_at, lesson_booking.sent_notices_at].find{|x|!x.nil?}
end
def stripe_description(lesson_booking)
diff --git a/ruby/lib/jam_ruby/models/teacher.rb b/ruby/lib/jam_ruby/models/teacher.rb
index 9061dc5a0..09515a4ba 100644
--- a/ruby/lib/jam_ruby/models/teacher.rb
+++ b/ruby/lib/jam_ruby/models/teacher.rb
@@ -64,7 +64,7 @@ module JamRuby
query = User.unscoped.joins(:teacher)
# only show teachers with ready for session set to true
- query = query.where('teachers.ready_for_session_at IS NOT NULL')
+ query = query.where('teachers.ready_for_session_at IS NOT NULL').where('teachers.is_searchable = TRUE')
# always force GuitarCenter users to see only their school's teachers, regardless of what they picked
if user && (user.is_guitar_center_student? || (params[:onlyMySchool] && params[:onlyMySchool] != 'false' && user.school_id))
@@ -222,6 +222,7 @@ module JamRuby
teacher.price_per_month_120_cents = params[:price_per_month_120_cents] if params.key?(:price_per_month_120_cents)
teacher.teaches_test_drive = params[:teaches_test_drive] if params.key?(:teaches_test_drive)
teacher.test_drives_per_week = params[:test_drives_per_week] if params.key?(:test_drives_per_week)
+ teacher.is_searchable = params[:is_searchable] if params.key?(:is_searchable)
teacher.test_drives_per_week = 10 if !params.key?(:test_drives_per_week) # default to 10 in absence of others
if params.key?(:school_id)
teacher.school_id = params[:school_id]
diff --git a/web/app/assets/javascripts/profile.js b/web/app/assets/javascripts/profile.js
index c83fc68e9..7c8b905b3 100644
--- a/web/app/assets/javascripts/profile.js
+++ b/web/app/assets/javascripts/profile.js
@@ -100,6 +100,7 @@
var $btnEdit = $screen.find('.edit-profile-btn');
var $btnTeacherProfileEdit = $screen.find('.edit-teacher-profile-btn');
var $btnTeacherProfileView = $screen.find('.view-teacher-profile-btn');
+ var $toggleTeacherSearchEnabled = $screen.find('.teacher-search-enabled')
var $btnAddFriend = $screen.find('#btn-add-friend');
var $btnFollowUser = $screen.find('#btn-follow-user');
var $btnMessageUser = $screen.find('#btn-message-user');
@@ -232,9 +233,11 @@
$btnTeacherProfileEdit.show();
if (isTeacher()) {
$btnTeacherProfileView.show();
+ $toggleTeacherSearchEnabled.show()
}
else {
$btnTeacherProfileView.hide();
+ $toggleTeacherSearchEnabled.hide()
}
$btnAddFriend.hide();
$btnFollowUser.hide();
@@ -332,6 +335,11 @@
window.ProfileActions.startProfileEdit('experience', true)
return false;
})
+ $toggleTeacherSearchEnabled.find('input').change(function(e) {
+ var $check = $(this)
+ rest.updateTeacher({id: user.teacher.id, is_searchable: $check.is(':checked')})
+ .fail(app.ajaxError);
+ })
}
function playSoundCloudFile(e) {
@@ -520,6 +528,7 @@
renderPerformanceSamples();
renderOnlinePresence();
renderInterests();
+ renderTeacherSearch();
}
}
@@ -565,6 +574,23 @@
}
}
+ function renderTeacherSearch()
+ {
+ if(isTeacher())
+ {
+ if(user.teacher.is_searchable )
+ {
+ $toggleTeacherSearchEnabled.find('input').attr('checked', 'checked')
+ }
+ else
+ {
+ $toggleTeacherSearchEnabled.find('input').removeAttr('checked')
+ }
+
+
+ }
+
+ }
function renderMusicalExperience() {
profileUtils.renderMusicalExperience(user, $screen, isCurrentUser())
}
diff --git a/web/app/assets/javascripts/react-components/LessonBooking.js.jsx.coffee b/web/app/assets/javascripts/react-components/LessonBooking.js.jsx.coffee
index a110ae8e0..0171cf344 100644
--- a/web/app/assets/javascripts/react-components/LessonBooking.js.jsx.coffee
+++ b/web/app/assets/javascripts/react-components/LessonBooking.js.jsx.coffee
@@ -401,11 +401,14 @@ UserStore = context.UserStore
otherCountered: () ->
@myself().id == @counterer().id
+ adminCanceled: () ->
+ this.state.booking?.canceled_by_admin?
+
studentCanceled: () ->
- @canceler().id == @student().id
+ @canceler()?.id == @student().id
selfCanceled: () ->
- @canceler().id == @myself().id
+ @canceler()?.id == @myself().id
studentMadeDefaultSlot: () ->
@student()?.id == @defaultSlot()?.proposer_id
@@ -513,7 +516,7 @@ UserStore = context.UserStore
else if @isCounter()
@counterer().id == @myself().id
else if @isCanceled()
- @canceler().id == @myself().id
+ @canceler()?.id == @myself().id
else if @isSuspended()
@studentViewing()
else
@@ -544,7 +547,9 @@ UserStore = context.UserStore
messageBlock: (selfWroteMessage, message) ->
- if selfWroteMessage
+ if typeof selfWroteMessage == 'string'
+ whoSaid = selfWroteMessage + ' said:'
+ else if selfWroteMessage
whoSaid = "You said:"
else
whoSaid = "Message from #{this.other().first_name}:"
@@ -660,12 +665,16 @@ UserStore = context.UserStore
if !photo_url?
photo_url = '/assets/shared/avatar_generic.png'
+ if user?
+ name = user.name
+ else
+ name = 'System'
`
A JamKazam administrator canceled this lesson request.
` + else if @studentViewing() if @studentCanceled() action = `You canceled this lesson request.
` else @@ -1062,7 +1073,7 @@ UserStore = context.UserStore if @studentViewing() - if @studentCanceled() + if @adminCanceled() || @studentCanceled() blurb = `We're sorry this scheduling attempt did not working out for you. Please search our community of instructors to find someone else who looks like a good fit for you, and submit a new lesson request
` else blurb = `We're sorry this instructor has declined your request. Please search our community of instructors to find someone else who looks like a good fit for you, and submit a new lesson request
` @@ -1073,11 +1084,16 @@ UserStore = context.UserStore {blurb} SEARCH INSTRUCTORS NOW ` + cancelerUser = null + if this.adminCanceled() + cancelerUser = 'System' + else + cancelerUser = this.selfCanceled() `