sip on user match mailer

This commit is contained in:
Nuwan 2023-01-04 21:41:57 +05:30
parent bbab6cdb9f
commit 46202a2373
20 changed files with 312 additions and 190 deletions

View File

@ -1,2 +0,0 @@
BUNDLE_GEMFILE=Gemfile.alt
BUNDLE_RUBY

View File

@ -87,7 +87,6 @@ gem 'sendgrid_toolkit', '>= 1.1.1'
gem 'stripe'
gem 'zip-codes'
gem 'elasticsearch'
gem 'logging', '1.7.2'

View File

@ -0,0 +1,8 @@
class AddSubscribeEmailForUserMatch < ActiveRecord::Migration
def self.up
execute("ALTER TABLE users ADD COLUMN subscribe_email_for_user_match BOOLEAN DEFAULT FALSE;")
end
def self.down
execute("ALTER TABLE users DROP COLUMN subscribe_email_for_user_match;")
end
end

View File

@ -0,0 +1,18 @@
class CreateUserMatchEmailSendings < ActiveRecord::Migration
def self.up
execute(<<-SQL
CREATE TABLE public.user_match_email_sendings (
id character varying(64) DEFAULT public.uuid_generate_v4() PRIMARY KEY NOT NULL,
sent_user_ids varchar[],
total_recipients integer,
created_at timestamp without time zone DEFAULT now() NOT NULL,
completed_at timestamp without time zone
);
SQL
)
end
def self.down
execute("DROP TABLE public.user_match_email_sendings")
end
end

View File

@ -0,0 +1,9 @@
class AddUserMatchEmailSentAt < ActiveRecord::Migration
def self.up
execute("ALTER TABLE users ADD COLUMN user_match_email_sent_at timestamp without time zone;")
end
def self.down
execute("ALTER TABLE users DROP COLUMN user_match_email_sent_at;")
end
end

View File

@ -73,6 +73,7 @@ require "jam_ruby/resque/scheduled/hourly_job"
require "jam_ruby/resque/scheduled/minutely_job"
require "jam_ruby/resque/scheduled/daily_session_emailer"
require "jam_ruby/resque/scheduled/new_musician_emailer"
require "jam_ruby/resque/scheduled/new_musician_match_emailer"
require "jam_ruby/resque/scheduled/music_session_reminder"
require "jam_ruby/resque/scheduled/music_session_scheduler"
require "jam_ruby/resque/scheduled/active_music_session_cleaner"
@ -116,6 +117,8 @@ require "jam_ruby/lib/desk_multipass"
require "jam_ruby/lib/ip"
require "jam_ruby/lib/subscription_message"
require "jam_ruby/lib/stats.rb"
require "jam_ruby/lib/email_new_musician_match"
require "jam_ruby/lib/musician_filter"
require "jam_ruby/amqp/amqp_connection_manager"
require "jam_ruby/database"
require "jam_ruby/message_factory"

View File

@ -399,6 +399,18 @@ module JamRuby
end
end
def new_musicians_match(user, musicians_data)
@user, @musicians_data = user, musicians_data
sendgrid_recipients([user.email])
sendgrid_substitute('@USERID', [user.id])
sendgrid_unique_args :type => "new_musicians_match"
mail(:to => user.email, :subject => EmailNewMusicianMatch.subject) do |format|
format.text
format.html
end
end
#################################### NOTIFICATION EMAILS ####################################
def friend_request(user, msg, friend_request_id)
return if !user.subscribe_email

View File

@ -0,0 +1 @@
EMAIL BODY HERE: <%= @musicians_data.inspect -%>

View File

@ -0,0 +1 @@
EMAIL BODY HERE: <%= @musicians_data.inspect -%>

View File

@ -0,0 +1,63 @@
module JamRuby
class EmailNewMusicianMatch
PER_PAGE = 20
JOINED_WITHIN_DAYS = ""
ACTIVE_WITHIN_DAYS = ""
def self.subject
"New musicians with good Internet connections to you have joined JamKazam!"
end
def self.send_new_musicians
params = {
latency_good: true,
latency_fair: true,
latency_high: false,
proficiency_beginner: true,
proficiency_intermediate: true,
proficiency_expert: true,
from_location: false,
joined_within_days: JOINED_WITHIN_DAYS,
active_within_days: ACTIVE_WITHIN_DAYS,
limit: PER_PAGE
}
begin
nextOffset = 0
email_sending = UserMatchEmailSending.most_recent
if email_sending.completed?
email_sending = UserMatchEmailSending.create
end
recipients = User.where(subscribe_email: true, subscribe_email_for_user_match: true).where("users.id NOT IN ?", email_sending.sent_user_ids)
#User.where(email: "nuwan@jamkazam.com").each do |user|
recipients.order("updated_at DESC, last_join_session_at DESC").each do |user|
ip = '127.0.0.1' #TODO: get this from user data?
matched_musician_data = []
while !nextOffset.nil? && nextOffset >= 0 do
params.merge!({ offset: nextOffset })
search, latency_data, nextOffset = JamRuby::MusicianFilter.filter(user, ip, params)
matched_musician_data << [search, latency_data] if search.results.size > 0
end
if matched_musician_data.size > 0
UserMailer.new_musicians_match(user, matched_musician_data).deliver_now
user.update_column(:user_match_email_sent_at, Time.now)
email_sending.sent_user_ids.push(user.id)
email_sending.save!
end
end
email_sending.total_recipients = email_sending.sent_user_ids.size
email_sending.completed_at = Time.now
email_sending.save!
rescue => exception
raise exception
end
end
end
end

View File

@ -1,5 +1,5 @@
module JamRuby
class MusiciansFilter
class MusicianFilter
LATENCY_SCORES = {
good: { label: 'GOOD', min: 0, max: 40 },
@ -9,20 +9,87 @@ module JamRuby
unknown: { label: 'UNKNOWN', min: -2, max: -2 }
};
#ATTN: Rails.application.config is out side to the JamRuby module. Is it a good decision to use
#application confis here?
def self.filter(user, remote_ip, params)
latency_good = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_good])
latency_fair = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_fair])
latency_high = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_high])
offset = [params[:offset].to_i, 0].max
limit = [params[:limit].to_i, 20].max
filter_params = {}
filter_params.merge!(from_location: params[:from_location] ? '1' : '0')
genres = params[:genres]
filter_params.merge!(genres: genres) if genres
beginner = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:proficiency_beginner])
intermediate = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:proficiency_intermediate])
expert = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:proficiency_expert])
proficiency_levels = []
proficiency_levels.push(1) if beginner
proficiency_levels.push(2) if intermediate
proficiency_levels.push(3) if expert
instruments = params[:instruments]
if instruments && instruments.any? && proficiency_levels.any?
inst = []
instruments.each do |ii|
proficiency_levels.each do |pl|
inst << { id: ii[:value], proficiency: pl}
end
end
filter_params.merge!(instruments: inst)
end
filter_params.merge!(joined_within_days: params[:joined_within_days]) unless params[:joined_within_days].blank?
filter_params.merge!(active_within_days: params[:active_within_days]) unless params[:active_within_days].blank?
begin
#bm = Benchmark.measure do
result = JamRuby::MusicianFilter.users_latency_data(user, remote_ip, latency_good, latency_fair, latency_high, filter_params, offset, limit)
latency_data = result[:data]
nextOffset = result[:next]
user_ids = latency_data.map{ |l_data| l_data[:user_id] }
#end
# Bugsnag.notify("search_users_benchmark") do |report|
# report.severity = "info"
# report.add_tab(:benchmark, benchmark: bm.to_s)
# end if Rails.env.production?
sobj = JamRuby::MusicianSearch.user_search_filter(user)
search = sobj.user_search_results(user_ids)
[search, latency_data, nextOffset]
rescue => exception
logger.debug("Latency exception: #{exception.message}")
Bugsnag.notify(exception) do |report|
report.severity = "error"
report.add_tab(:latency, {
params: params,
user_id: user.id,
name: user.name,
url: filter_latency_url,
})
end
raise exception
end
end
def self.users_latency_data(user_obj, remote_ip, latency_good, latency_fair, latency_high, filter_opts, offset, limit)
latency_data = []
filter_latency_url = "#{Rails.application.config.latency_data_host}/search_users"
filter_latency_url = "#{APP_CONFIG.latency_data_host}/search_users"
uri = URI(filter_latency_url)
begin
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true if Rails.application.config.latency_data_host.start_with?("https://")
http.use_ssl = true if APP_CONFIG.latency_data_host.start_with?("https://")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Basic #{Rails.application.config.latency_data_host_auth_code}"
req["Authorization"] = "Basic #{APP_CONFIG.latency_data_host_auth_code}"
req["Content-Type"] = "application/json"
req_params = {
@ -44,8 +111,6 @@ module JamRuby
response = http.request(req)
#debugger
if response.is_a?(Net::HTTPOK) || response.is_a?(Net::HTTPSuccess)
json_body = JSON.parse(response.body)
graph_db_users = json_body['users']
@ -88,91 +153,6 @@ module JamRuby
rescue => exception
raise exception
end
latency_data
end
def self.filter(params)
user_id = params[:user_id]
remote_ip = params[:remote_ip]
raise Exception("This query request should contain user_id and remote_ip") if user_id.blank? || remote_ip.blank?
user = User.find(user_id)
latency_good = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_good])
latency_fair = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_fair])
latency_high = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_high])
offset = [params[:offset].to_i, 0].max
limit = [params[:limit].to_i, 20].max
filter_params = {}
filter_params.merge!(from_location: params[:from_location] ? '1' : '0')
genres = params[:genres]
filter_params.merge!(genres: genres) if genres
beginner = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:proficiency_beginner])
intermediate = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:proficiency_intermediate])
expert = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:proficiency_expert])
proficiency_levels = []
proficiency_levels.push(1) if beginner
proficiency_levels.push(2) if intermediate
proficiency_levels.push(3) if expert
instruments = params[:instruments]
#debugger
if instruments && instruments.any? && proficiency_levels.any?
inst = []
instruments.each do |ii|
proficiency_levels.each do |pl|
inst << { id: ii[:value], proficiency: pl}
end
end
filter_params.merge!(instruments: inst)
end
filter_params.merge!(joined_within_days: params[:joined_within_days]) unless params[:joined_within_days].blank?
filter_params.merge!(active_within_days: params[:active_within_days]) unless params[:active_within_days].blank?
@latency_data = []
begin
#bm = Benchmark.measure do
result = users_latency_data(user, remote_ip, latency_good, latency_fair, latency_high, filter_params, offset, limit)
@latency_data = result[:data]
@nextOffset = result[:next]
user_ids = @latency_data.map{ |l_data| l_data[:user_id] }
#end
# Bugsnag.notify("search_users_benchmark") do |report|
# report.severity = "info"
# report.add_tab(:benchmark, benchmark: bm.to_s)
# end if Rails.env.production?
sobj = MusicianSearch.user_search_filter(user)
#@search = sobj.search_results_page(filter_params, page, user_ids)
#debugger
@search = sobj.user_search_results(user_ids)
respond_with @search, responder: ApiResponder, status: 201, template: 'api_search/filter'
rescue => exception
logger.debug("Latency exception: #{exception.message}")
Bugsnag.notify(exception) do |report|
report.severity = "error"
report.add_tab(:latency, {
params: params,
user_id: user.id,
name: user.name,
url: filter_latency_url,
})
end
render json: {}, status: 500
end
end
end
end

View File

@ -1,9 +0,0 @@
module JamRuby
class EmailNewMusicianMatch
def self.send_new_musician
end
end
end

View File

@ -0,0 +1,11 @@
module JamRuby
class UserMatchEmailSending < ActiveRecord::Base
def completed?
!completed_at.nil?
end
def self.most_recent
UserMatchEmailSending.order(created_at: :desc).first
end
end
end

View File

@ -7,7 +7,7 @@ module JamRuby
def self.perform
@@log.debug("waking up")
EmailNewMusicianMatch.send_new_musician
EmailNewMusicianMatch.send_new_musicians
@@log.debug("done")
end

View File

@ -4,7 +4,7 @@
require "spec_helper"
describe "RenderMailers", :slow => true do
describe "RenderMailers" do
let(:user) { FactoryGirl.create(:user) }
let(:school) {FactoryGirl.create(:school, education:true)}
@ -16,7 +16,7 @@ describe "RenderMailers", :slow => true do
describe "UserMailer emails" do
before(:each) do
user.update_email = "my_new_email@jamkazam.com"
#user.update_email = "my_new_email@jamkazam.com"
UserMailer.deliveries.clear
end
@ -53,6 +53,32 @@ describe "RenderMailers", :slow => true do
it { @filename="friend_request"; UserMailer.friend_request(user, 'So and so has sent you a friend request.', friend_request.id).deliver_now }
end
# describe "sending about new musicians with good latency to the user", focus: true do
# let(:user) { User.find_by(email: "nuwan@jamkazam.com") }
# let(:params) {
# {latency_good: true,
# latency_fair: true,
# latency_high: false,
# proficiency_beginner: true,
# proficiency_intermediate: true,
# proficiency_expert: true,
# from_location: false,
# joined_within_days: "",
# active_within_days: "",
# limit: 20,
# offset: 0}
# }
# let(:ip){ "127.0.0.1" }
# it{
# @filename="new_musicians_match"
# search, latency_data, nextOffset = JamRuby::MusicianFilter.filter(user, ip, params)
# matched_musician_data = []
# matched_musician_data << [search, latency_data]
# UserMailer.new_musicians_match(user, matched_musician_data).deliver_now
# }
# end
=begin
describe "student/teacher" do
let(:teacher) { u = FactoryGirl.create(:teacher); u.user }

View File

@ -182,7 +182,7 @@ end
# gem 'rack-timeout'
#end
gem 'ffi', '1.12.0'
gem 'ffi', '1.14.0'
group :development, :test do
gem 'rspec-rails' #, require: "rspec/rails" #, '2.14.2'

View File

@ -459,7 +459,9 @@ GEM
mime-types (3.3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2021.0212)
mimemagic (0.3.5)
mimemagic (0.4.3)
nokogiri (~> 1)
rake
mini_mime (1.0.2)
mini_portile2 (2.4.0)
minitest (5.14.3)

View File

@ -5,7 +5,7 @@ class ApiSearchController < ApiController
respond_to :json
include LatencyHelper
#include LatencyHelper
def index
if 1 == params[Search::PARAM_MUSICIAN].to_i || 1 == params[Search::PARAM_BAND].to_i
@ -95,94 +95,96 @@ class ApiSearchController < ApiController
end
end
# def filter
# latency_good = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_good])
# latency_fair = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_fair])
# latency_high = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_high])
# offset = [params[:offset].to_i, 0].max
# limit = [params[:limit].to_i, 20].max
# filter_params = {}
# filter_params.merge!(from_location: params[:from_location] ? '1' : '0')
# genres = params[:genres]
# filter_params.merge!(genres: genres) if genres
# # if genres && genres.any?
# # genres.map!{|genre| {id: genre} }
# # filter_params.merge!(genres: genres)
# # end
# beginner = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:proficiency_beginner])
# intermediate = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:proficiency_intermediate])
# expert = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:proficiency_expert])
# proficiency_levels = []
# proficiency_levels.push(1) if beginner
# proficiency_levels.push(2) if intermediate
# proficiency_levels.push(3) if expert
# instruments = params[:instruments]
# #debugger
# if instruments && instruments.any? && proficiency_levels.any?
# inst = []
# instruments.each do |ii|
# proficiency_levels.each do |pl|
# inst << { id: ii[:value], proficiency: pl}
# end
# end
# filter_params.merge!(instruments: inst)
# end
# filter_params.merge!(joined_within_days: params[:joined_within_days]) unless params[:joined_within_days].blank?
# filter_params.merge!(active_within_days: params[:active_within_days]) unless params[:active_within_days].blank?
# @latency_data = []
# begin
# #bm = Benchmark.measure do
# result = JamRuby::MusicianFilter.users_latency_data(current_user, request.remote_ip, latency_good, latency_fair, latency_high, filter_params, offset, limit)
# @latency_data = result[:data]
# @nextOffset = result[:next]
# user_ids = @latency_data.map{ |l_data| l_data[:user_id] }
# #end
# # Bugsnag.notify("search_users_benchmark") do |report|
# # report.severity = "info"
# # report.add_tab(:benchmark, benchmark: bm.to_s)
# # end if Rails.env.production?
# sobj = MusicianSearch.user_search_filter(current_user)
# #@search = sobj.search_results_page(filter_params, page, user_ids)
# debugger
# @search = sobj.user_search_results(user_ids)
# respond_with @search, responder: ApiResponder, status: 201, template: 'api_search/filter'
# rescue => exception
# logger.debug("Latency exception: #{exception.message}")
# Bugsnag.notify(exception) do |report|
# report.severity = "error"
# report.add_tab(:latency, {
# params: params,
# user_id: current_user.id,
# name: current_user.name,
# url: filter_latency_url,
# })
# end
# render json: {}, status: 500
# end
# end
def filter
latency_good = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_good])
latency_fair = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_fair])
latency_high = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:latency_high])
offset = [params[:offset].to_i, 0].max
limit = [params[:limit].to_i, 20].max
filter_params = {}
filter_params.merge!(from_location: params[:from_location] ? '1' : '0')
genres = params[:genres]
filter_params.merge!(genres: genres) if genres
# if genres && genres.any?
# genres.map!{|genre| {id: genre} }
# filter_params.merge!(genres: genres)
# end
beginner = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:proficiency_beginner])
intermediate = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:proficiency_intermediate])
expert = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[:proficiency_expert])
proficiency_levels = []
proficiency_levels.push(1) if beginner
proficiency_levels.push(2) if intermediate
proficiency_levels.push(3) if expert
instruments = params[:instruments]
#debugger
if instruments && instruments.any? && proficiency_levels.any?
inst = []
instruments.each do |ii|
proficiency_levels.each do |pl|
inst << { id: ii[:value], proficiency: pl}
end
end
filter_params.merge!(instruments: inst)
end
filter_params.merge!(joined_within_days: params[:joined_within_days]) unless params[:joined_within_days].blank?
filter_params.merge!(active_within_days: params[:active_within_days]) unless params[:active_within_days].blank?
@latency_data = []
begin
#bm = Benchmark.measure do
result = users_latency_data(latency_good, latency_fair, latency_high, filter_params, offset, limit)
@latency_data = result[:data]
@nextOffset = result[:next]
user_ids = @latency_data.map{ |l_data| l_data[:user_id] }
#end
# Bugsnag.notify("search_users_benchmark") do |report|
# report.severity = "info"
# report.add_tab(:benchmark, benchmark: bm.to_s)
# end if Rails.env.production?
sobj = MusicianSearch.user_search_filter(current_user)
#@search = sobj.search_results_page(filter_params, page, user_ids)
#debugger
@search = sobj.user_search_results(user_ids)
@search, @latency_data, @nextOffset = JamRuby::MusicianFilter.filter(current_user, request.remote_ip, params)
respond_with @search, responder: ApiResponder, status: 201, template: 'api_search/filter'
rescue => exception
logger.debug("Latency exception: #{exception.message}")
Bugsnag.notify(exception) do |report|
report.severity = "error"
report.add_tab(:latency, {
params: params,
user_id: current_user.id,
name: current_user.name,
url: filter_latency_url,
})
end
rescue
render json: {}, status: 500
end
end
private
def filter_latency_url
"#{Rails.application.config.latency_data_host}/search_users"
end
end

View File

@ -86,7 +86,6 @@ module LatencyHelper
raise exception
end
latency_data
end
end

View File

@ -133,9 +133,8 @@ describe "Musician Filter API", type: :request do
expect(JSON.parse(response.body)["musicians"].size).to eq(8)
end
it "filter musicians when no latency option is selected" do
it "filter musicians when no latency option is selected", focus: true do
post '/api/filter.json', { latency_good: false, latency_fair: false, latency_high: false }
expect(JSON.parse(response.body)["musicians"].size).to eq(8)
expect(JSON.parse(response.body)["musicians"][0]["latency_data"]).not_to eq(nil)
expect(JSON.parse(response.body)["musicians"][0]["latency_data"]["audio_latency"]).not_to eq(nil)