Compare commits

..

No commits in common. "develop" and "feature/db-optimize" have entirely different histories.

1980 changed files with 45011 additions and 227204 deletions

View File

@ -1,25 +0,0 @@
name: Build Admin
on:
push:
branches:
- develop
jobs:
build:
runs-on: dagger
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v4
- name: Install Dagger
run: |
curl -L https://dl.dagger.io/dagger/install.sh | sh
sudo mv bin/dagger /usr/local/bin/
- name: Login to Gitea Registry
run: echo "${{ gitea.token }}" | docker login git.staging.jamkazam.com -u ${{ gitea.actor }} --password-stdin
- name: Build and Publish with Dagger
working-directory: ./admin
run: |
dagger call build-local --source=. --repo-root=../ publish --address=git.staging.jamkazam.com/seth/jam-cloud-admin:latest

View File

@ -1,41 +0,0 @@
name: Environment Orchestrator
on: [push]
jobs:
orchestrate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Component Deployment Gatekeeper
run: |
# JAM_CLUSTER_ENV should be set to 'staging' or 'production' in the Gitea Runner
ENV="${JAM_CLUSTER_ENV:-staging}"
echo "🌐 Cluster Environment: $ENV"
# 1. Extract modes for this environment
ADMIN_MODE=$(jq -r ".environments.$ENV.admin" .jk-deploy.json)
WEB_MODE=$(jq -r ".environments.$ENV.web" .jk-deploy.json)
WS_MODE=$(jq -r ".environments.$ENV.[\"websocket-gateway\"]" .jk-deploy.json)
# 2. Conditional Execution
if [ "$ADMIN_MODE" == "short-circuit" ]; then
echo "⚡ ADMIN: Short-circuit detected. Deploying immediately..."
cd admin && dagger call ship --source=.
else
echo "⏸️ ADMIN: Mode is $ADMIN_MODE. Skipping short-circuit deploy."
fi
if [ "$WEB_MODE" == "short-circuit" ]; then
echo "⚡ WEB: Short-circuit detected. Deploying immediately..."
cd web && dagger call ship --source=.
else
echo "⏸️ WEB: Mode is $WEB_MODE. Skipping short-circuit deploy."
fi
if [ "$WS_MODE" == "short-circuit" ]; then
echo "⚡ WS-GATEWAY: Short-circuit detected. Deploying immediately..."
cd websocket-gateway && just ship
else
echo "⏸️ WS-GATEWAY: Mode is $WS_MODE. Skipping short-circuit deploy."
fi

View File

@ -1,8 +0,0 @@
name: Test Runner
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- run: echo "Runner is working!"

4
.gitignore vendored
View File

@ -8,7 +8,3 @@ HTML
coverage coverage
dump.rdb dump.rdb
working.png working.png
ruby/.rails5-gems
web/.rails5-gems
websocket-gateway/.rails5-gems
.pg_data/

View File

@ -1 +0,0 @@
2.4.1

3
admin/.gitignore vendored
View File

@ -21,6 +21,3 @@ artifacts
.idea .idea
BUILD_NUMBER BUILD_NUMBER
# Gemfile.lock # Gemfile.lock
Gemfile.alt.lock
.byebug_history
.ruby-version

7
admin/.rakeTasks Normal file

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
2.4.1

View File

@ -1,55 +1,29 @@
source 'http://rubygems.org' source 'http://rubygems.org'
source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/' source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/'
ruby_version = ENV["JAM_RUBY_VERSION"]
ruby_version = "2.3.1" if ruby_version.nil?
ruby ruby_version
devenv = ENV["BUILD_NUMBER"].nil? devenv = ENV["BUILD_NUMBER"].nil?
if devenv if devenv
#gem 'jam_db', :path=> "../db/target/ruby_package" gem 'jam_db', :path=> "../db/target/ruby_package"
gem 'jampb', :path => "../pb/target/ruby/jampb" gem 'jampb', :path => "../pb/target/ruby/jampb"
gem 'jam_ruby', :path => "../ruby" gem 'jam_ruby', :path => "../ruby"
else else
source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/' do gem 'jam_db', "0.1.#{ENV["BUILD_NUMBER"]}"
#gem 'jam_db', "0.1.#{ENV["BUILD_NUMBER"]}" gem 'jampb', "0.1.#{ENV["BUILD_NUMBER"]}"
gem 'jampb', "0.1.#{ENV["BUILD_NUMBER"]}" gem 'jam_ruby', "0.1.#{ENV["BUILD_NUMBER"]}"
gem 'jam_ruby', "0.1.#{ENV["BUILD_NUMBER"]}" ENV['NOKOGIRI_USE_SYSTEM_LIBRARIES'] ||= "true"
ENV['NOKOGIRI_USE_SYSTEM_LIBRARIES'] ||= "true"
end
end end
gem 'activeadmin_addons' gem 'activeadmin_addons'
gem 'json', '1.8.6' gem 'json', '1.8.6'
gem 'rails', '= 4.2.8' gem 'rails', '> 4.2'
gem 'protected_attributes' gem 'protected_attributes'
gem 'rails-observers' gem 'rails-observers'
# PINNED TO SUPPORT BOTH 2.3.1 and 2.4.1 Ruby simultaneously
# This should be the same in ruby/admin/web/websocket-gateway
#######
gem 'nokogiri', '1.10.10' # added to pin before 1.11.0, which requires at leaost ruby 2.5. unpin we go above
gem 'sprockets', '3.6.3' # added to pin before 4.0.0, which requiurse at least ruby 2.5
gem 'fog-brightbox', '0.11.0' # pinned until we are on ruby 2.5; then remove
gem 'faraday', '0.9.2' # pinned untnil we are on ruby 2.5; then remove
gem 'ruby-prof', '0.15.9' # pinned until we are on ruby 2.5; then remove
gem 'rubyzip', '1.2.1' # pinned until we are on ruby 2.5; then remove
gem 'recurly', '2.18.16' # should upgrade to 3.x when we have time to validaate
gem 'icalendar', '2.4.0' # pinned until we are on ruby 2.5; then remove
gem 'email_validator', '1.6.0' # pinned until we are on ruby 2.5, then remove
gem 'redis', '3.3.3' # pinned until we are on 2.5; then remove
gem 'redis-namespace', '1.5.3' # pinned until we are on 2.5; then remove
gem 'oj', '3.1.3' # pinned until we are on 2.5; then remove
gem 'bcrypt', '3.1.15'
gem 'sass-rails', '5.0.7' # compiler mismatch issue between build and www
gem 'sass', '3.5.5 '# compiler mismatch issue between build and www
#######
gem 'bootstrap-sass', '2.0.4' gem 'bootstrap-sass', '2.0.4'
gem 'bcrypt-ruby', '3.0.1'
gem 'sass-rails' #, '~> 3.2.3'
gem 'coffee-rails' #, '~> 3.2.1' gem 'coffee-rails' #, '~> 3.2.1'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes # See https://github.com/sstephenson/execjs#readme for more supported runtimes
@ -58,7 +32,6 @@ gem 'coffee-rails' #, '~> 3.2.1'
gem 'kickbox' gem 'kickbox'
gem 'uglifier' #, '>= 1.0.3' gem 'uglifier' #, '>= 1.0.3'
gem 'net-ssh' gem 'net-ssh'
gem 'sprockets-rails', '2.3.2'
# this version is pinned due to this: https://github.com/gregbell/active_admin/issues/1939 # this version is pinned due to this: https://github.com/gregbell/active_admin/issues/1939
gem 'coffee-script-source' #, '~> 1.4.0' # ADD THIS LINE, 1.5.0 doesn't compile ActiveAdmin JavaScript files gem 'coffee-script-source' #, '~> 1.4.0' # ADD THIS LINE, 1.5.0 doesn't compile ActiveAdmin JavaScript files
@ -72,17 +45,15 @@ gem 'jquery-ui-rails'# , '5.0.5' #, '4.2.1'
gem 'jquery-rails'# , '4.1.1' # both this and jquery-ui-rails are pinned; if you unpin, jquery/autocomplete is missing during precomplie gem 'jquery-rails'# , '4.1.1' # both this and jquery-ui-rails are pinned; if you unpin, jquery/autocomplete is missing during precomplie
gem 'rails-jquery-autocomplete' # This is the maintained version of rails3-jquery-autocomplete gem 'rails-jquery-autocomplete' # This is the maintained version of rails3-jquery-autocomplete
gem 'activeadmin' #, '1.0.0.pre4'# github: 'activeadmin', branch: 'master' gem 'activeadmin' #, '1.0.0.pre4'# github: 'activeadmin', branch: 'master'
gem 'activeadmin-searchable_select'
gem 'mime-types', '1.25' gem 'mime-types', '1.25'
#gem 'meta_search' #gem 'meta_search'
gem 'fog' gem 'fog', "~> 1.32.0"
gem 'xmlrpc'
gem 'unf', '0.1.3' #optional fog dependency gem 'unf', '0.1.3' #optional fog dependency
gem 'country-select' gem 'country-select'
gem 'aasm' #, '3.0.16' gem 'aasm' #, '3.0.16'
gem 'postgres-copy', '0.6.0' gem 'postgres-copy', '0.6.0'
gem 'aws-sdk', '~> 1' gem 'aws-sdk', '~> 1'
gem 'bugsnag', '5.3.2' gem 'bugsnag'
gem 'gon' gem 'gon'
gem 'cocoon' gem 'cocoon'
gem 'haml-rails' gem 'haml-rails'
@ -93,13 +64,7 @@ gem 'resque-lonely_job', '~> 1.0.0'
gem 'eventmachine', '1.2.3' gem 'eventmachine', '1.2.3'
gem 'amqp', '0.9.8' gem 'amqp', '0.9.8'
#gem 'logging-rails', :require => 'logging/rails' #gem 'logging-rails', :require => 'logging/rails'
#gem 'pg_migrate', '0.1.14' gem 'pg_migrate', '0.1.14'
if ENV["MODERN_OS"] == "1"
gem 'pg', '0.21.0'
else
# on mac, bundle config build.pg --with-cflags="-Wno-error=implicit-function-declaration"
gem 'pg', '0.17.1', :platform => [:mri, :mswin, :mingw]
end
gem 'ruby-protocol-buffers', '1.2.2' gem 'ruby-protocol-buffers', '1.2.2'
gem 'sendgrid', '1.2.0' gem 'sendgrid', '1.2.0'
gem 'geokit-rails' gem 'geokit-rails'
@ -107,20 +72,20 @@ gem 'postgres_ext' #, '1.0.0'
gem 'resque_mailer' gem 'resque_mailer'
gem 'rest-client' gem 'rest-client'
gem 'iso-639' gem 'iso-639'
gem 'rubyzip'
gem 'sanitize' gem 'sanitize'
gem 'slim' gem 'slim'
#gem 'influxdb', '0.1.8' #gem 'influxdb', '0.1.8'
#gem 'influxdb-rails', '0.1.10' #gem 'influxdb-rails', '0.1.10'
gem 'influxdb', '0.3.14' gem 'influxdb-rails'
gem 'influxdb-rails', '0.1.12' gem 'recurly', '~> 2'
gem 'sendgrid_toolkit', '>= 1.1.1' gem 'sendgrid_toolkit', '>= 1.1.1'
gem 'stripe' gem 'stripe'
gem 'zip-codes' gem 'zip-codes'
gem 'email_validator'
gem 'best_in_place' #, github: 'bernat/best_in_place' gem 'best_in_place' #, github: 'bernat/best_in_place'
gem 'auto_strip_attributes', '2.6.0' gem 'auto_strip_attributes', '2.6.0'
gem 'elasticsearch'
gem 'logging', '1.7.2'
#group :libv8 do #group :libv8 do
# gem 'libv8', "~> 4.5.95" # gem 'libv8', "~> 4.5.95"
@ -145,14 +110,14 @@ end
#gem 'debugger' # not working with 2.1.2p95 #gem 'debugger' # not working with 2.1.2p95
group :development, :test do group :development, :test do
gem 'capybara', '2.13.0' gem 'capybara'
gem 'rspec-rails' #, '2.14.2' gem 'rspec-rails' #, '2.14.2'
gem 'jasmine', '1.3.1' gem 'jasmine', '1.3.1'
gem 'execjs', '1.4.0' gem 'execjs', '1.4.0'
#gem 'therubyracer' #, '0.11.0beta8' #gem 'therubyracer' #, '0.11.0beta8'
gem 'factory_girl_rails' # , '4.1.0' gem 'factory_girl_rails' # , '4.1.0'
gem 'database_cleaner' #, '0.7.0' gem 'database_cleaner' #, '0.7.0'
gem 'launchy', '2.4.3' # can unpin when go to ruby 2.4+ gem 'launchy'
gem 'faker', '1.3.0' gem 'faker', '1.3.0'
gem 'puma' gem 'puma'
gem 'test-unit' gem 'test-unit'

View File

@ -1,172 +0,0 @@
source 'http://rubygems.org'
source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/'
ruby_version = ENV["JAM_RUBY_VERSION"]
ruby_version = "2.3.1" if ruby_version.nil?
ruby ruby_version
devenv = ENV["BUILD_NUMBER"].nil?
if devenv
#gem 'jam_db', :path=> "../db/target/ruby_package"
gem 'jampb', :path => "../pb/target/ruby/jampb"
gem 'jam_ruby', :path => "../ruby"
else
source 'https://jamjam:blueberryjam@int.jamkazam.com/gems/' do
#gem 'jam_db', "0.1.#{ENV["BUILD_NUMBER"]}"
gem 'jampb', "0.1.#{ENV["BUILD_NUMBER"]}"
gem 'jam_ruby', "0.1.#{ENV["BUILD_NUMBER"]}"
ENV['NOKOGIRI_USE_SYSTEM_LIBRARIES'] ||= "true"
end
end
gem 'activeadmin_addons'
gem 'json', '1.8.6'
gem 'rails', '= 4.2.8'
gem 'protected_attributes'
gem 'rails-observers'
# PINNED TO SUPPORT BOTH 2.3.1 and 2.4.1 Ruby simultaneously
# This should be the same in ruby/admin/web/websocket-gateway
#######
gem 'nokogiri', '1.10.10' # added to pin before 1.11.0, which requires at leaost ruby 2.5. unpin we go above
gem 'sprockets', '3.6.3' # added to pin before 4.0.0, which requiurse at least ruby 2.5
gem 'fog-brightbox', '0.11.0' # pinned until we are on ruby 2.5; then remove
gem 'faraday', '0.9.2' # pinned untnil we are on ruby 2.5; then remove
gem 'ruby-prof', '0.15.9' # pinned until we are on ruby 2.5; then remove
gem 'rubyzip', '1.2.1' # pinned until we are on ruby 2.5; then remove
gem 'recurly', '2.18.16' # should upgrade to 3.x when we have time to validaate
gem 'icalendar', '2.4.0' # pinned until we are on ruby 2.5; then remove
gem 'email_validator', '1.6.0' # pinned until we are on ruby 2.5, then remove
gem 'redis', '3.3.3' # pinned until we are on 2.5; then remove
gem 'redis-namespace', '1.5.3' # pinned until we are on 2.5; then remove
gem 'oj', '3.1.3' # pinned until we are on 2.5; then remove
gem 'bcrypt', '3.1.15'
gem 'sass-rails', '5.0.7' # compiler mismatch issue between build and www
gem 'sass', '3.5.5 '# compiler mismatch issue between build and www
#######
gem 'bootstrap-sass', '2.0.4'
gem 'coffee-rails' #, '~> 3.2.1'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', :platforms => :ruby
gem 'kickbox'
gem 'uglifier' #, '>= 1.0.3'
gem 'net-ssh'
gem 'sprockets-rails', '2.3.2'
# this version is pinned due to this: https://github.com/gregbell/active_admin/issues/1939
gem 'coffee-script-source' #, '~> 1.4.0' # ADD THIS LINE, 1.5.0 doesn't compile ActiveAdmin JavaScript files
gem 'devise' #, '3.3.0'
gem 'will_paginate' #, '3.0.3'
gem 'bootstrap-will_paginate', '0.0.6'
gem 'carrierwave', '0.11.2' #, '0.9.0'
gem 'carrierwave_direct'
gem 'uuidtools', '2.1.2'
gem 'jquery-ui-rails'# , '5.0.5' #, '4.2.1'
gem 'jquery-rails'# , '4.1.1' # both this and jquery-ui-rails are pinned; if you unpin, jquery/autocomplete is missing during precomplie
gem 'rails-jquery-autocomplete' # This is the maintained version of rails3-jquery-autocomplete
gem 'activeadmin' #, '1.0.0.pre4'# github: 'activeadmin', branch: 'master'
gem 'activeadmin-searchable_select'
gem 'mime-types', '1.25'
#gem 'meta_search'
gem 'fog'
gem 'xmlrpc'
gem 'unf', '0.1.3' #optional fog dependency
gem 'country-select'
gem 'aasm' #, '3.0.16'
gem 'postgres-copy', '0.6.0'
gem 'aws-sdk', '~> 1'
gem 'bugsnag', '5.3.2'
gem 'gon'
gem 'cocoon'
gem 'haml-rails'
gem 'resque'
gem 'resque-retry'
gem 'resque-failed-job-mailer'
gem 'resque-lonely_job', '~> 1.0.0'
gem 'eventmachine', '1.2.3'
gem 'amqp', '0.9.8'
#gem 'logging-rails', :require => 'logging/rails'
#gem 'pg_migrate', '0.1.14'
if ENV["MODERN_OS"] == "1"
gem 'pg', '0.21.0'
else
# on mac, bundle config build.pg --with-cflags="-Wno-error=implicit-function-declaration"
gem 'pg', '0.17.1', :platform => [:mri, :mswin, :mingw]
end
gem 'ruby-protocol-buffers', '1.2.2'
gem 'sendgrid', '1.2.0'
gem 'geokit-rails'
gem 'postgres_ext' #, '1.0.0'
gem 'resque_mailer'
gem 'rest-client'
gem 'iso-639'
gem 'sanitize'
gem 'slim'
#gem 'influxdb', '0.1.8'
#gem 'influxdb-rails', '0.1.10'
gem 'influxdb', '0.3.14'
gem 'influxdb-rails', '0.1.12'
gem 'sendgrid_toolkit', '>= 1.1.1'
gem 'stripe'
gem 'zip-codes'
gem 'best_in_place' #, github: 'bernat/best_in_place'
gem 'auto_strip_attributes', '2.6.0'
gem 'elasticsearch'
gem 'logging', '1.7.2'
#group :libv8 do
# gem 'libv8', "~> 4.5.95"
#end
# To use Jbuilder templates for JSON
# gem 'jbuilder'
group :production do
gem 'unicorn'
end
group :package do
gem 'fpm'
end
# Deploy with Capistrano
# gem 'capistrano'
# To use debugger
#gem 'debugger' # not working with 2.1.2p95
group :development, :test do
gem 'capybara', '2.13.0'
gem 'rspec-rails' #, '2.14.2'
gem 'jasmine', '1.3.1'
gem 'execjs', '1.4.0'
#gem 'therubyracer' #, '0.11.0beta8'
gem 'factory_girl_rails' # , '4.1.0'
gem 'database_cleaner' #, '0.7.0'
gem 'launchy', '2.4.3' # can unpin when go to ruby 2.4+
gem 'faker', '1.3.0'
gem 'puma'
gem 'test-unit'
end
group :test do
gem 'simplecov', '~> 0.7.1'
gem 'simplecov-rcov'
# gem 'capybara-webkit'
# gem 'capybara-screenshot', '0.3.22' # 1.0.0 broke compat with rspec. maybe we need newer rspec
# gem 'poltergeist'
end
gem 'pry'
gem 'pry-remote'
gem 'pry-stack_explorer'
#gem 'pry-debugger'

View File

@ -1,3 +1,9 @@
PATH
remote: ../db/target/ruby_package
specs:
jam_db (0.1.1)
pg_migrate (= 0.1.14)
PATH PATH
remote: ../pb/target/ruby/jampb remote: ../pb/target/ruby/jampb
specs: specs:
@ -13,80 +19,70 @@ GEM
remote: https://jamjam:blueberryjam@int.jamkazam.com/gems/ remote: https://jamjam:blueberryjam@int.jamkazam.com/gems/
specs: specs:
CFPropertyList (2.3.6) CFPropertyList (2.3.6)
aasm (5.1.1) aasm (4.12.3)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
actionmailer (4.2.8) actionmailer (4.2.10)
actionpack (= 4.2.8) actionpack (= 4.2.10)
actionview (= 4.2.8) actionview (= 4.2.10)
activejob (= 4.2.8) activejob (= 4.2.10)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 1.0, >= 1.0.5)
actionpack (4.2.8) actionpack (4.2.10)
actionview (= 4.2.8) actionview (= 4.2.10)
activesupport (= 4.2.8) activesupport (= 4.2.10)
rack (~> 1.6) rack (~> 1.6)
rack-test (~> 0.6.2) rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (4.2.8) actionview (4.2.10)
activesupport (= 4.2.8) activesupport (= 4.2.10)
builder (~> 3.1) builder (~> 3.1)
erubis (~> 2.7.0) erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.3) rails-html-sanitizer (~> 1.0, >= 1.0.3)
active_material (1.4.2) activeadmin (1.2.1)
activeadmin (1.4.3)
arbre (>= 1.1.1) arbre (>= 1.1.1)
coffee-rails coffee-rails
formtastic (~> 3.1) formtastic (~> 3.1)
formtastic_i18n formtastic_i18n
inherited_resources (>= 1.9.0) inherited_resources (~> 1.7)
jquery-rails (>= 4.2.0) jquery-rails (>= 4.2.0)
kaminari (>= 0.15) kaminari (>= 0.15, < 2.0)
railties (>= 4.2, < 5.3) railties (>= 4.2, < 5.2)
ransack (>= 1.8.7) ransack (~> 1.3)
sass (~> 3.1) sass (~> 3.1)
sprockets (< 4.1) sprockets (< 4.1)
activeadmin-searchable_select (1.4.0) activeadmin_addons (1.1.2)
activeadmin (>= 1.x, < 3)
jquery-rails (>= 3.0, < 5)
select2-rails (~> 4.0)
activeadmin_addons (1.7.1)
active_material
railties railties
require_all (~> 1.5) require_all
sass
select2-rails (~> 4.0) select2-rails (~> 4.0)
xdan-datetimepicker-rails (~> 2.5.1) xdan-datetimepicker-rails (~> 2.5.1)
activejob (4.2.8) activejob (4.2.10)
activesupport (= 4.2.8) activesupport (= 4.2.10)
globalid (>= 0.3.0) globalid (>= 0.3.0)
activemodel (4.2.8) activemodel (4.2.10)
activesupport (= 4.2.8) activesupport (= 4.2.10)
builder (~> 3.1) builder (~> 3.1)
activerecord (4.2.8) activerecord (4.2.10)
activemodel (= 4.2.8) activemodel (= 4.2.10)
activesupport (= 4.2.8) activesupport (= 4.2.10)
arel (~> 6.0) arel (~> 6.0)
activesupport (4.2.8) activesupport (4.2.10)
i18n (~> 0.7) i18n (~> 0.7)
minitest (~> 5.1) minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4) thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1) tzinfo (~> 1.1)
addressable (2.7.0) addressable (2.5.2)
public_suffix (>= 2.0.2, < 5.0) public_suffix (>= 2.0.2, < 4.0)
aliyun-sdk (0.8.0)
nokogiri (~> 1.6)
rest-client (~> 2.0)
amq-client (0.9.12) amq-client (0.9.12)
amq-protocol (>= 1.2.0) amq-protocol (>= 1.2.0)
eventmachine eventmachine
amq-protocol (2.3.2) amq-protocol (2.3.0)
amqp (0.9.8) amqp (0.9.8)
amq-client (~> 0.9.5) amq-client (~> 0.9.5)
amq-protocol (>= 0.9.4) amq-protocol (>= 0.9.4)
eventmachine eventmachine
arbre (1.2.1) arbre (1.1.1)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
arel (6.0.4) arel (6.0.4)
arr-pm (0.0.10) arr-pm (0.0.10)
@ -98,8 +94,9 @@ GEM
aws-sdk-v1 (1.67.0) aws-sdk-v1 (1.67.0)
json (~> 1.4) json (~> 1.4)
nokogiri (~> 1) nokogiri (~> 1)
backports (3.20.2) backports (3.11.1)
bcrypt (3.1.15) bcrypt (3.1.11)
bcrypt-ruby (3.0.1)
best_in_place (3.1.1) best_in_place (3.1.1)
actionpack (>= 3.2) actionpack (>= 3.2)
railties (>= 3.2) railties (>= 3.2)
@ -108,8 +105,9 @@ GEM
bootstrap-sass (2.0.4.0) bootstrap-sass (2.0.4.0)
bootstrap-will_paginate (0.0.6) bootstrap-will_paginate (0.0.6)
will_paginate will_paginate
bugsnag (5.3.2) bugsnag (6.6.3)
builder (3.2.4) concurrent-ruby (~> 1.0)
builder (3.2.3)
cabin (0.9.0) cabin (0.9.0)
capybara (2.13.0) capybara (2.13.0)
addressable addressable
@ -124,15 +122,15 @@ GEM
json (>= 1.7) json (>= 1.7)
mime-types (>= 1.16) mime-types (>= 1.16)
mimemagic (>= 0.3.0) mimemagic (>= 0.3.0)
carrierwave_direct (1.0.0) carrierwave_direct (0.0.15)
carrierwave (~> 0.11) carrierwave
fog-aws fog
cause (0.1) uuidtools
childprocess (0.9.0) childprocess (0.8.0)
ffi (~> 1.0, >= 1.0.11) ffi (~> 1.0, >= 1.0.11)
clamp (1.0.1) clamp (1.0.1)
cocoon (1.2.15) cocoon (1.2.11)
coderay (1.1.3) coderay (1.1.2)
coffee-rails (4.2.2) coffee-rails (4.2.2)
coffee-script (>= 2.2.0) coffee-script (>= 2.2.0)
railties (>= 4.0.0) railties (>= 4.0.0)
@ -140,36 +138,28 @@ GEM
coffee-script-source coffee-script-source
execjs execjs
coffee-script-source (1.12.2) coffee-script-source (1.12.2)
concurrent-ruby (1.1.8) concurrent-ruby (1.0.5)
country-select (1.2.1) country-select (1.1.1)
crass (1.0.6) crass (1.0.3)
database_cleaner (1.99.0) database_cleaner (1.6.2)
debug_inspector (1.0.0) debug_inspector (0.0.3)
devise (4.7.3) devise (4.4.1)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
railties (>= 4.1.0) railties (>= 4.1.0, < 5.2)
responders responders
warden (~> 1.2.3) warden (~> 1.2.3)
diff-lcs (1.4.4) diff-lcs (1.3)
domain_name (0.5.20190701) domain_name (0.5.20170404)
unf (>= 0.0.5, < 1.0.0) unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.6) dotenv (2.2.1)
elasticsearch (7.4.0)
elasticsearch-api (= 7.4.0)
elasticsearch-transport (= 7.4.0)
elasticsearch-api (7.4.0)
multi_json
elasticsearch-transport (7.4.0)
faraday
multi_json
email_validator (1.6.0) email_validator (1.6.0)
activemodel activemodel
erubis (2.7.0) erubis (2.7.0)
et-orbi (1.2.4) et-orbi (1.0.9)
tzinfo tzinfo
eventmachine (1.2.3) eventmachine (1.2.3)
excon (0.79.0) excon (0.60.0)
execjs (1.4.0) execjs (1.4.0)
multi_json (~> 1.0) multi_json (~> 1.0)
factory_girl (4.9.0) factory_girl (4.9.0)
@ -179,31 +169,22 @@ GEM
railties (>= 3.0.0) railties (>= 3.0.0)
faker (1.3.0) faker (1.3.0)
i18n (~> 0.5) i18n (~> 0.5)
faraday (0.9.2) faraday (0.14.0)
multipart-post (>= 1.2, < 3) multipart-post (>= 1.2, < 3)
ffi (1.12.2) ffi (1.9.18)
fission (0.5.0) fission (0.5.0)
CFPropertyList (~> 2.2) CFPropertyList (~> 2.2)
fog (1.41.0) fog (1.32.0)
fog-aliyun (>= 0.1.0)
fog-atmos fog-atmos
fog-aws (>= 0.6.0) fog-aws (>= 0.6.0)
fog-brightbox (~> 0.4) fog-brightbox (~> 0.4)
fog-cloudatcost (~> 0.1.0) fog-core (~> 1.32)
fog-core (~> 1.45) fog-ecloud (= 0.1.1)
fog-digitalocean (>= 0.3.0) fog-google (>= 0.0.2)
fog-dnsimple (~> 1.0)
fog-dynect (~> 0.0.2)
fog-ecloud (~> 0.1)
fog-google (<= 0.1.0)
fog-internet-archive
fog-joyent
fog-json fog-json
fog-local fog-local
fog-openstack
fog-powerdns (>= 0.1.1) fog-powerdns (>= 0.1.1)
fog-profitbricks fog-profitbricks
fog-rackspace
fog-radosgw (>= 0.0.2) fog-radosgw (>= 0.0.2)
fog-riakcs fog-riakcs
fog-sakuracloud (>= 0.0.4) fog-sakuracloud (>= 0.0.4)
@ -213,85 +194,44 @@ GEM
fog-terremark fog-terremark
fog-vmfusion fog-vmfusion
fog-voxel fog-voxel
fog-vsphere (>= 0.4.0)
fog-xenserver
fog-xml (~> 0.1.1) fog-xml (~> 0.1.1)
ipaddress (~> 0.5) ipaddress (~> 0.5)
json (>= 1.8, < 2.0) nokogiri (~> 1.5, >= 1.5.11)
fog-aliyun (0.3.19)
aliyun-sdk (~> 0.8.0)
fog-core
fog-json
ipaddress (~> 0.8)
xml-simple (~> 1.1)
fog-atmos (0.1.0) fog-atmos (0.1.0)
fog-core fog-core
fog-xml fog-xml
fog-aws (2.0.1) fog-aws (2.0.0)
fog-core (~> 1.38) fog-core (~> 1.38)
fog-json (~> 1.0) fog-json (~> 1.0)
fog-xml (~> 0.1) fog-xml (~> 0.1)
ipaddress (~> 0.8) ipaddress (~> 0.8)
fog-brightbox (0.11.0) fog-brightbox (0.14.0)
fog-core (~> 1.22) fog-core (~> 1.22)
fog-json fog-json
inflecto (~> 0.0.2) inflecto (~> 0.0.2)
fog-cloudatcost (0.1.2)
fog-core (~> 1.36)
fog-json (~> 1.0)
fog-xml (~> 0.1)
ipaddress (~> 0.8)
fog-core (1.45.0) fog-core (1.45.0)
builder builder
excon (~> 0.58) excon (~> 0.58)
formatador (~> 0.2) formatador (~> 0.2)
fog-digitalocean (0.4.0) fog-ecloud (0.1.1)
fog-core
fog-xml
fog-google (0.6.0)
fog-core fog-core
fog-json fog-json
fog-xml fog-xml
ipaddress (>= 0.5) fog-json (1.0.2)
fog-dnsimple (1.0.0) fog-core (~> 1.0)
fog-core (~> 1.38)
fog-json (~> 1.0)
fog-dynect (0.0.3)
fog-core
fog-json
fog-xml
fog-ecloud (0.3.0)
fog-core
fog-xml
fog-google (0.1.0)
fog-core
fog-json
fog-xml
fog-internet-archive (0.0.2)
fog-core
fog-json
fog-xml
fog-joyent (0.0.1)
fog-core (~> 1.42)
fog-json (>= 1.0)
fog-json (1.2.0)
fog-core
multi_json (~> 1.10) multi_json (~> 1.10)
fog-local (0.6.0) fog-local (0.4.0)
fog-core (>= 1.27, < 3.0) fog-core (~> 1.27)
fog-openstack (0.3.10) fog-powerdns (0.1.1)
fog-core (>= 1.45, <= 2.1.0) fog-core (~> 1.27)
fog-json (>= 1.0) fog-json (~> 1.0)
ipaddress (>= 0.8) fog-xml (~> 0.1)
fog-powerdns (0.2.0)
fog-core
fog-json
fog-xml
fog-profitbricks (4.1.1) fog-profitbricks (4.1.1)
fog-core (~> 1.42) fog-core (~> 1.42)
fog-json (~> 1.0) fog-json (~> 1.0)
fog-rackspace (0.1.6)
fog-core (>= 1.35)
fog-json (>= 1.0)
fog-xml (>= 0.1)
ipaddress (>= 0.8)
fog-radosgw (0.0.5) fog-radosgw (0.0.5)
fog-core (>= 1.21.0) fog-core (>= 1.21.0)
fog-json fog-json
@ -321,13 +261,6 @@ GEM
fog-voxel (0.1.0) fog-voxel (0.1.0)
fog-core fog-core
fog-xml fog-xml
fog-vsphere (3.5.0)
fog-core
rbvmomi (>= 1.9, < 3)
fog-xenserver (1.0.0)
fog-core
fog-xml
xmlrpc
fog-xml (0.1.3) fog-xml (0.1.3)
fog-core fog-core
nokogiri (>= 1.5.11, < 2.0.0) nokogiri (>= 1.5.11, < 2.0.0)
@ -335,35 +268,28 @@ GEM
formtastic (3.1.5) formtastic (3.1.5)
actionpack (>= 3.2.13) actionpack (>= 3.2.13)
formtastic_i18n (0.6.0) formtastic_i18n (0.6.0)
fpm (1.12.0) fpm (1.9.3)
arr-pm (~> 0.0.10) arr-pm (~> 0.0.10)
backports (>= 2.6.2) backports (>= 2.6.2)
cabin (>= 0.6.0) cabin (>= 0.6.0)
childprocess (< 1.0.0) childprocess
clamp (~> 1.0.0) clamp (~> 1.0.0)
ffi (~> 1.12.0) ffi
git (>= 1.3.0, < 2.0) json (>= 1.7.7, < 2.0)
json (>= 1.7.7, < 3.0)
pleaserun (~> 0.0.29) pleaserun (~> 0.0.29)
ruby-xz (~> 0.2.3) ruby-xz
stud stud
fugit (1.4.2) geokit (1.11.0)
et-orbi (~> 1.1, >= 1.1.8) geokit-rails (2.3.0)
raabro (~> 1.4)
geokit (1.13.1)
geokit-rails (2.3.2)
geokit (~> 1.5) geokit (~> 1.5)
rails (>= 3.0) rails (>= 3.0)
git (1.8.1) globalid (0.4.1)
rchardet (~> 1.8)
globalid (0.4.2)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
gon (6.4.0) gon (6.2.0)
actionpack (>= 3.0.20) actionpack (>= 3.0)
i18n (>= 0.7)
multi_json multi_json
request_store (>= 1.0) request_store (>= 1.0)
haml (5.2.1) haml (5.0.4)
temple (>= 0.8.0) temple (>= 0.8.0)
tilt tilt
haml-rails (1.0.0) haml-rails (1.0.0)
@ -372,65 +298,61 @@ GEM
haml (>= 4.0.6, < 6.0) haml (>= 4.0.6, < 6.0)
html2haml (>= 1.0.1) html2haml (>= 1.0.1)
railties (>= 4.0.1) railties (>= 4.0.1)
has_scope (0.7.2) has_scope (0.7.1)
actionpack (>= 4.1) actionpack (>= 4.1, < 5.2)
activesupport (>= 4.1) activesupport (>= 4.1, < 5.2)
html2haml (2.2.0) html2haml (2.2.0)
erubis (~> 2.7.0) erubis (~> 2.7.0)
haml (>= 4.0, < 6) haml (>= 4.0, < 6)
nokogiri (>= 1.6.0) nokogiri (>= 1.6.0)
ruby_parser (~> 3.5) ruby_parser (~> 3.5)
http-accept (1.7.0)
http-cookie (1.0.3) http-cookie (1.0.3)
domain_name (~> 0.5) domain_name (~> 0.5)
httparty (0.16.2) httparty (0.15.6)
multi_xml (>= 0.5.2) multi_xml (>= 0.5.2)
i18n (0.9.5) i18n (0.9.3)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
icalendar (2.4.0)
inflecto (0.0.2) inflecto (0.0.2)
influxdb (0.3.14) influxdb (0.5.3)
cause influxdb-rails (0.4.3)
json influxdb (~> 0.5.0)
influxdb-rails (0.1.12) railties (> 3)
influxdb (~> 0.3.0) inherited_resources (1.8.0)
railties actionpack (>= 4.2, <= 5.2)
inherited_resources (1.9.0)
actionpack (>= 4.2, < 5.3)
has_scope (~> 0.6) has_scope (~> 0.6)
railties (>= 4.2, < 5.3) railties (>= 4.2, <= 5.2)
responders responders
insist (1.0.0) insist (1.0.0)
io-like (0.3.1) io-like (0.3.0)
ipaddress (0.8.3) ipaddress (0.8.3)
iso-639 (0.3.5) iso-639 (0.2.8)
jasmine (1.3.1) jasmine (1.3.1)
jasmine-core (~> 1.3.1) jasmine-core (~> 1.3.1)
rack (~> 1.0) rack (~> 1.0)
rspec (>= 1.3.1) rspec (>= 1.3.1)
selenium-webdriver (>= 0.1.3) selenium-webdriver (>= 0.1.3)
jasmine-core (1.3.1) jasmine-core (1.3.1)
jquery-rails (4.4.0) jquery-rails (4.3.1)
rails-dom-testing (>= 1, < 3) rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0) railties (>= 4.2.0)
thor (>= 0.14, < 2.0) thor (>= 0.14, < 2.0)
jquery-ui-rails (6.0.1) jquery-ui-rails (6.0.1)
railties (>= 3.2.16) railties (>= 3.2.16)
json (1.8.6) json (1.8.6)
kaminari (1.2.1) kaminari (1.1.1)
activesupport (>= 4.1.0) activesupport (>= 4.1.0)
kaminari-actionview (= 1.2.1) kaminari-actionview (= 1.1.1)
kaminari-activerecord (= 1.2.1) kaminari-activerecord (= 1.1.1)
kaminari-core (= 1.2.1) kaminari-core (= 1.1.1)
kaminari-actionview (1.2.1) kaminari-actionview (1.1.1)
actionview actionview
kaminari-core (= 1.2.1) kaminari-core (= 1.1.1)
kaminari-activerecord (1.2.1) kaminari-activerecord (1.1.1)
activerecord activerecord
kaminari-core (= 1.2.1) kaminari-core (= 1.1.1)
kaminari-core (1.2.1) kaminari-core (1.1.1)
kgio (2.11.3) kgio (2.11.1)
kickbox (2.0.4) kickbox (2.0.3)
faraday (~> 0.9) faraday (~> 0.9)
json (>= 1.8) json (>= 1.8)
launchy (2.4.3) launchy (2.4.3)
@ -438,81 +360,82 @@ GEM
little-plugger (1.1.4) little-plugger (1.1.4)
logging (1.7.2) logging (1.7.2)
little-plugger (>= 1.1.3) little-plugger (>= 1.1.3)
loofah (2.9.0) loofah (2.1.1)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
mail (2.7.1) mail (2.7.0)
mini_mime (>= 0.1.1) mini_mime (>= 0.1.1)
method_source (1.0.0) method_source (0.9.0)
mime-types (1.25) mime-types (1.25)
mimemagic (0.3.5) mimemagic (0.3.2)
mini_mime (1.0.2) mini_mime (1.0.0)
mini_portile2 (2.4.0) mini_portile2 (2.3.0)
minitest (5.14.3) minitest (5.11.2)
mono_logger (1.1.0) mono_logger (1.1.0)
multi_json (1.15.0) multi_json (1.13.1)
multi_xml (0.6.0) multi_xml (0.6.0)
multipart-post (2.1.1) multipart-post (2.0.0)
mustache (0.99.8) mustache (0.99.8)
net-ssh (6.1.0) net-ssh (4.2.0)
netrc (0.11.0) netrc (0.11.0)
nio4r (2.5.2) nokogiri (1.8.1)
nokogiri (1.10.10) mini_portile2 (~> 2.3.0)
mini_portile2 (~> 2.4.0) nokogumbo (1.4.13)
nokogumbo (2.0.4) nokogiri
nokogiri (~> 1.8, >= 1.8.4)
oj (3.1.3)
optimist (3.0.1)
orm_adapter (0.5.0) orm_adapter (0.5.0)
pg (0.17.1) pg (0.17.1)
pg_array_parser (0.0.9) pg_array_parser (0.0.9)
pleaserun (0.0.31) pg_migrate (0.1.14)
logging (= 1.7.2)
pg (= 0.17.1)
thor
pleaserun (0.0.30)
cabin (> 0) cabin (> 0)
clamp clamp
dotenv dotenv
insist insist
mustache (= 0.99.8) mustache (= 0.99.8)
stud stud
polyamorous (1.3.3)
activerecord (>= 3.0)
postgres-copy (0.6.0) postgres-copy (0.6.0)
activerecord (>= 3.0.0) activerecord (>= 3.0.0)
pg pg
rails (>= 3.0.0) rails (>= 3.0.0)
responders responders
postgres_ext (3.0.1) postgres_ext (3.0.0)
activerecord (~> 4.0) activerecord (>= 4.0.0)
arel (>= 4.0.1) arel (>= 4.0.1)
pg_array_parser (~> 0.0.9) pg_array_parser (~> 0.0.9)
power_assert (2.0.0) power_assert (1.1.1)
protected_attributes (1.1.4) protected_attributes (1.1.4)
activemodel (>= 4.0.1, < 5.0) activemodel (>= 4.0.1, < 5.0)
pry (0.14.0) pry (0.11.3)
coderay (~> 1.1) coderay (~> 1.1.0)
method_source (~> 1.0) method_source (~> 0.9.0)
pry-remote (0.1.8) pry-remote (0.1.8)
pry (~> 0.9) pry (~> 0.9)
slop (~> 3.0) slop (~> 3.0)
pry-stack_explorer (0.4.12) pry-stack_explorer (0.4.9.2)
binding_of_caller (~> 0.7) binding_of_caller (>= 0.7)
pry (~> 0.13) pry (>= 0.9.11)
public_suffix (4.0.6) public_suffix (3.0.1)
puma (5.2.1) puma (3.11.2)
nio4r (~> 2.0) rack (1.6.8)
raabro (1.4.0) rack-protection (1.5.3)
rack (1.6.13)
rack-protection (1.5.5)
rack rack
rack-test (0.6.3) rack-test (0.6.3)
rack (>= 1.0) rack (>= 1.0)
rails (4.2.8) rails (4.2.10)
actionmailer (= 4.2.8) actionmailer (= 4.2.10)
actionpack (= 4.2.8) actionpack (= 4.2.10)
actionview (= 4.2.8) actionview (= 4.2.10)
activejob (= 4.2.8) activejob (= 4.2.10)
activemodel (= 4.2.8) activemodel (= 4.2.10)
activerecord (= 4.2.8) activerecord (= 4.2.10)
activesupport (= 4.2.8) activesupport (= 4.2.10)
bundler (>= 1.3.0, < 2.0) bundler (>= 1.3.0, < 2.0)
railties (= 4.2.8) railties (= 4.2.10)
sprockets-rails sprockets-rails
rails-deprecated_sanitizer (1.0.3) rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha) activesupport (>= 4.2.0.alpha)
@ -520,43 +443,38 @@ GEM
activesupport (>= 4.2.0, < 5.0) activesupport (>= 4.2.0, < 5.0)
nokogiri (~> 1.6) nokogiri (~> 1.6)
rails-deprecated_sanitizer (>= 1.0.1) rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.3.0) rails-html-sanitizer (1.0.3)
loofah (~> 2.3) loofah (~> 2.0)
rails-jquery-autocomplete (1.0.5) rails-jquery-autocomplete (1.0.3)
rails (>= 3.2) rails (>= 3.2)
rails-observers (0.1.5) rails-observers (0.1.5)
activemodel (>= 4.0) activemodel (>= 4.0)
railties (4.2.8) railties (4.2.10)
actionpack (= 4.2.8) actionpack (= 4.2.10)
activesupport (= 4.2.8) activesupport (= 4.2.10)
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
raindrops (0.19.1) raindrops (0.19.0)
rake (13.0.3) rake (12.3.0)
ransack (1.8.10) ransack (1.8.6)
actionpack (>= 3.0, < 5.2) actionpack (>= 3.0)
activerecord (>= 3.0, < 5.2) activerecord (>= 3.0)
activesupport (>= 3.0, < 5.2) activesupport (>= 3.0)
i18n i18n
rb-fsevent (0.10.4) polyamorous (~> 1.3.2)
rb-inotify (0.10.1) rb-fsevent (0.10.2)
ffi (~> 1.0) rb-inotify (0.9.10)
rbvmomi (2.4.1) ffi (>= 0.5.0, < 2)
builder (~> 3.0) recurly (2.18.18)
json (>= 1.8) redis (4.0.1)
nokogiri (~> 1.5) redis-namespace (1.6.0)
optimist (~> 3.0) redis (>= 3.0.4)
rchardet (1.8.0) request_store (1.4.0)
recurly (2.18.16)
redis (3.3.3)
redis-namespace (1.5.3)
redis (~> 3.0, >= 3.0.4)
request_store (1.5.0)
rack (>= 1.4) rack (>= 1.4)
require_all (1.5.0) require_all (1.5.0)
responders (2.4.1) responders (2.4.0)
actionpack (>= 4.2.0, < 6.0) actionpack (>= 4.2.0, < 5.3)
railties (>= 4.2.0, < 6.0) railties (>= 4.2.0, < 5.3)
resque (1.27.4) resque (1.27.4)
mono_logger (~> 1.0) mono_logger (~> 1.0)
multi_json (~> 1.0) multi_json (~> 1.0)
@ -566,57 +484,55 @@ GEM
resque-failed-job-mailer (0.0.3) resque-failed-job-mailer (0.0.3)
resque-lonely_job (1.0.2) resque-lonely_job (1.0.2)
resque (>= 1.2) resque (>= 1.2)
resque-retry (1.7.4) resque-retry (1.5.0)
resque (>= 1.25, < 3.0) resque (~> 1.25)
resque-scheduler (~> 4.0) resque-scheduler (~> 4.0)
resque-scheduler (4.4.0) resque-scheduler (4.3.1)
mono_logger (~> 1.0) mono_logger (~> 1.0)
redis (>= 3.3) redis (>= 3.3, < 5)
resque (>= 1.26) resque (~> 1.26)
rufus-scheduler (~> 3.2) rufus-scheduler (~> 3.2)
resque_mailer (2.4.3) resque_mailer (2.4.3)
actionmailer (>= 3.0) actionmailer (>= 3.0)
activesupport (>= 3.0) activesupport (>= 3.0)
rest-client (2.1.0) rest-client (2.0.2)
http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0) http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0) mime-types (>= 1.16, < 4.0)
netrc (~> 0.8) netrc (~> 0.8)
rspec (3.10.0) rspec (3.7.0)
rspec-core (~> 3.10.0) rspec-core (~> 3.7.0)
rspec-expectations (~> 3.10.0) rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.10.0) rspec-mocks (~> 3.7.0)
rspec-core (3.10.1) rspec-core (3.7.1)
rspec-support (~> 3.10.0) rspec-support (~> 3.7.0)
rspec-expectations (3.10.1) rspec-expectations (3.7.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0) rspec-support (~> 3.7.0)
rspec-mocks (3.10.2) rspec-mocks (3.7.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0) rspec-support (~> 3.7.0)
rspec-rails (4.0.2) rspec-rails (3.7.2)
actionpack (>= 4.2) actionpack (>= 3.0)
activesupport (>= 4.2) activesupport (>= 3.0)
railties (>= 4.2) railties (>= 3.0)
rspec-core (~> 3.10) rspec-core (~> 3.7.0)
rspec-expectations (~> 3.10) rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.10) rspec-mocks (~> 3.7.0)
rspec-support (~> 3.10) rspec-support (~> 3.7.0)
rspec-support (3.10.2) rspec-support (3.7.0)
ruby-prof (0.15.9)
ruby-protocol-buffers (1.2.2) ruby-protocol-buffers (1.2.2)
ruby-xz (0.2.3) ruby-xz (0.2.3)
ffi (~> 1.9) ffi (~> 1.9)
io-like (~> 0.3) io-like (~> 0.3)
ruby_parser (3.15.1) ruby_parser (3.10.1)
sexp_processor (~> 4.9) sexp_processor (~> 4.9)
rubyzip (1.2.1) rubyzip (1.2.1)
rufus-scheduler (3.7.0) rufus-scheduler (3.4.2)
fugit (~> 1.1, >= 1.1.6) et-orbi (~> 1.0)
sanitize (5.2.3) sanitize (4.5.0)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.8.0) nokogiri (>= 1.4.4)
nokogumbo (~> 2.0) nokogumbo (~> 1.4.1)
sass (3.5.5) sass (3.5.5)
sass-listen (~> 4.0.0) sass-listen (~> 4.0.0)
sass-listen (4.0.0) sass-listen (4.0.0)
@ -628,15 +544,16 @@ GEM
sprockets (>= 2.8, < 4.0) sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0) sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3) tilt (>= 1.1, < 3)
select2-rails (4.0.13) select2-rails (4.0.3)
selenium-webdriver (3.14.0) thor (~> 0.14)
selenium-webdriver (3.8.0)
childprocess (~> 0.5) childprocess (~> 0.5)
rubyzip (~> 1.2) rubyzip (~> 1.0)
sendgrid (1.2.0) sendgrid (1.2.0)
json json
sendgrid_toolkit (1.4.0) sendgrid_toolkit (1.4.0)
httparty (>= 0.7.6) httparty (>= 0.7.6)
sexp_processor (4.15.2) sexp_processor (4.10.0)
simplecov (0.7.1) simplecov (0.7.1)
multi_json (~> 1.0) multi_json (~> 1.0)
simplecov-html (~> 0.7.1) simplecov-html (~> 0.7.1)
@ -647,33 +564,34 @@ GEM
rack (~> 1.5) rack (~> 1.5)
rack-protection (~> 1.4) rack-protection (~> 1.4)
tilt (>= 1.3, < 3) tilt (>= 1.3, < 3)
slim (4.1.0) slim (3.0.9)
temple (>= 0.7.6, < 0.9) temple (>= 0.7.6, < 0.9)
tilt (>= 2.0.6, < 2.1) tilt (>= 1.3.3, < 2.1)
slop (3.6.0) slop (3.6.0)
sprockets (3.6.3) sprockets (3.7.1)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
rack (> 1, < 3) rack (> 1, < 3)
sprockets-rails (2.3.2) sprockets-rails (3.2.1)
actionpack (>= 3.0) actionpack (>= 4.0)
activesupport (>= 3.0) activesupport (>= 4.0)
sprockets (>= 2.8, < 4.0) sprockets (>= 3.0.0)
stripe (5.29.1) stripe (3.9.1)
faraday (~> 0.10)
stud (0.0.23) stud (0.0.23)
temple (0.8.2) temple (0.8.0)
test-unit (3.4.0) test-unit (3.2.7)
power_assert power_assert
thor (1.1.0) thor (0.20.0)
thread_safe (0.3.6) thread_safe (0.3.6)
tilt (2.0.10) tilt (2.0.8)
tzinfo (1.2.9) tzinfo (1.2.4)
thread_safe (~> 0.1) thread_safe (~> 0.1)
uglifier (4.2.0) uglifier (4.1.4)
execjs (>= 0.3.0, < 3) execjs (>= 0.3.0, < 3)
unf (0.1.3) unf (0.1.3)
unf_ext unf_ext
unf_ext (0.0.7.7) unf_ext (0.0.7.4)
unicorn (5.8.0) unicorn (5.4.0)
kgio (~> 2.6) kgio (~> 2.6)
raindrops (~> 0.7) raindrops (~> 0.7)
uuidtools (2.1.2) uuidtools (2.1.2)
@ -681,14 +599,10 @@ GEM
rack (>= 1.0.0) rack (>= 1.0.0)
warden (1.2.7) warden (1.2.7)
rack (>= 1.0) rack (>= 1.0)
webrick (1.7.0) will_paginate (3.1.6)
will_paginate (3.3.0)
xdan-datetimepicker-rails (2.5.4) xdan-datetimepicker-rails (2.5.4)
jquery-rails jquery-rails
rails (>= 3.2.16) rails (>= 3.2.16)
xml-simple (1.1.8)
xmlrpc (0.3.2)
webrick
xpath (2.1.0) xpath (2.1.0)
nokogiri (~> 1.3) nokogiri (~> 1.3)
zip-codes (0.2.1) zip-codes (0.2.1)
@ -699,17 +613,16 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
aasm aasm
activeadmin activeadmin
activeadmin-searchable_select
activeadmin_addons activeadmin_addons
amqp (= 0.9.8) amqp (= 0.9.8)
auto_strip_attributes (= 2.6.0) auto_strip_attributes (= 2.6.0)
aws-sdk (~> 1) aws-sdk (~> 1)
bcrypt (= 3.1.15) bcrypt-ruby (= 3.0.1)
best_in_place best_in_place
bootstrap-sass (= 2.0.4) bootstrap-sass (= 2.0.4)
bootstrap-will_paginate (= 0.0.6) bootstrap-will_paginate (= 0.0.6)
bugsnag (= 5.3.2) bugsnag
capybara (= 2.13.0) capybara
carrierwave (= 0.11.2) carrierwave (= 0.11.2)
carrierwave_direct carrierwave_direct
cocoon cocoon
@ -718,23 +631,19 @@ DEPENDENCIES
country-select country-select
database_cleaner database_cleaner
devise devise
elasticsearch email_validator
email_validator (= 1.6.0)
eventmachine (= 1.2.3) eventmachine (= 1.2.3)
execjs (= 1.4.0) execjs (= 1.4.0)
factory_girl_rails factory_girl_rails
faker (= 1.3.0) faker (= 1.3.0)
faraday (= 0.9.2) fog (~> 1.32.0)
fog
fog-brightbox (= 0.11.0)
fpm fpm
geokit-rails geokit-rails
gon gon
haml-rails haml-rails
icalendar (= 2.4.0) influxdb-rails
influxdb (= 0.3.14)
influxdb-rails (= 0.1.12)
iso-639 iso-639
jam_db!
jam_ruby! jam_ruby!
jampb! jampb!
jasmine (= 1.3.1) jasmine (= 1.3.1)
@ -742,13 +651,10 @@ DEPENDENCIES
jquery-ui-rails jquery-ui-rails
json (= 1.8.6) json (= 1.8.6)
kickbox kickbox
launchy (= 2.4.3) launchy
logging (= 1.7.2)
mime-types (= 1.25) mime-types (= 1.25)
net-ssh net-ssh
nokogiri (= 1.10.10) pg_migrate (= 0.1.14)
oj (= 3.1.3)
pg (= 0.17.1)
postgres-copy (= 0.6.0) postgres-copy (= 0.6.0)
postgres_ext postgres_ext
protected_attributes protected_attributes
@ -756,12 +662,10 @@ DEPENDENCIES
pry-remote pry-remote
pry-stack_explorer pry-stack_explorer
puma puma
rails (= 4.2.8) rails (> 4.2)
rails-jquery-autocomplete rails-jquery-autocomplete
rails-observers rails-observers
recurly (= 2.18.16) recurly (~> 2)
redis (= 3.3.3)
redis-namespace (= 1.5.3)
resque resque
resque-failed-job-mailer resque-failed-job-mailer
resque-lonely_job (~> 1.0.0) resque-lonely_job (~> 1.0.0)
@ -769,19 +673,15 @@ DEPENDENCIES
resque_mailer resque_mailer
rest-client rest-client
rspec-rails rspec-rails
ruby-prof (= 0.15.9)
ruby-protocol-buffers (= 1.2.2) ruby-protocol-buffers (= 1.2.2)
rubyzip (= 1.2.1) rubyzip
sanitize sanitize
sass (= 3.5.5) sass-rails
sass-rails (= 5.0.7)
sendgrid (= 1.2.0) sendgrid (= 1.2.0)
sendgrid_toolkit (>= 1.1.1) sendgrid_toolkit (>= 1.1.1)
simplecov (~> 0.7.1) simplecov (~> 0.7.1)
simplecov-rcov simplecov-rcov
slim slim
sprockets (= 3.6.3)
sprockets-rails (= 2.3.2)
stripe stripe
test-unit test-unit
uglifier uglifier
@ -789,11 +689,7 @@ DEPENDENCIES
unicorn unicorn
uuidtools (= 2.1.2) uuidtools (= 2.1.2)
will_paginate will_paginate
xmlrpc
zip-codes zip-codes
RUBY VERSION
ruby 2.4.1p111
BUNDLED WITH BUNDLED WITH
1.17.3 1.17.1

View File

@ -6,9 +6,3 @@
require File.expand_path('../config/application', __FILE__) require File.expand_path('../config/application', __FILE__)
JamAdmin::Application.load_tasks JamAdmin::Application.load_tasks
require 'jam_ruby'
spec = Gem::Specification.find_by_name 'jam_ruby'
rakefile = "#{spec.gem_dir}/Rakefile"
load rakefile

View File

@ -1,161 +0,0 @@
module AdCampaignsHelper
def self.spacer(val, total)
percentage = ((val * 100) / total.to_f).round(1).to_s
('%-5.5s' % percentage).gsub(' ', '&nbsp;') + '%&nbsp;-&nbsp;' + val.to_s
end
def self.cac(campaign)
if campaign.subscribed && campaign.subscribed > 0
(campaign.spend/campaign.subscribed.to_f).round(2)
end
end
def self.cac_divide_by_ltv(campaign)
customer_ltv = GenericState.singleton.customer_ltv
if cac(campaign) && customer_ltv && customer_ltv > 0
return (cac(campaign)/customer_ltv.to_f).round(2)
end
end
def self.format_number(num)
if num
num.to_s.reverse.scan(/\d{3}|.+/).join(",").reverse
end
end
end
ActiveAdmin.register JamRuby::AdCampaign, as: 'AdCampaign' do
menu :label => 'Ad Campaigns', :parent => 'Reports'
before_filter :skip_sidebar!, :only => :index
config.batch_actions = false
config.clear_action_items!
config.sort_order = "users.origin_utm_campaign DESC"
config.per_page = 100
config.paginate = true
index do
div do
render 'customer_ltv'
end
column "Campaign" do |campaign|
campaign.origin_utm_campaign
end
column "Medium" do |campaign|
campaign.origin_utm_medium
end
column "End Date" do |campaign|
best_in_place campaign, :end_date, as: :date, url: inplace_update_admin_ad_campaigns_path(campaign: campaign.origin_utm_campaign, medium: campaign.origin_utm_medium), param: 'ad_campaign', classes: 'ac_bip'
end
column "Hard Date" do |campaign|
(campaign.end_date + 45.days).strftime('%Y-%m-%d') if campaign.end_date.present?
end
column "Subscribed" do |campaign|
raw(AdCampaignsHelper.spacer(campaign.subscribed, campaign.joined))
end
column "Spend" do |campaign|
best_in_place campaign, :spend, as: :input, url: inplace_update_admin_ad_campaigns_path(campaign: campaign.origin_utm_campaign, medium: campaign.origin_utm_medium), param: 'ad_campaign', display_with: Proc.new{|spend| number_to_currency(spend) }, classes: 'ac_bip'
end
column "CAC" do |campaign|
number_to_currency(AdCampaignsHelper.cac(campaign)) if AdCampaignsHelper.cac(campaign) && AdCampaignsHelper.cac(campaign) > 0
end
column "LTV/CAC" do |campaign|
AdCampaignsHelper.cac_divide_by_ltv(campaign)
end
column "Referred" do |campaign|
best_in_place campaign, :referred, as: :input, url: inplace_update_admin_ad_campaigns_path(campaign: campaign.origin_utm_campaign, medium: campaign.origin_utm_medium), param: 'ad_campaign', display_with: Proc.new{|referred| AdCampaignsHelper.format_number(referred) }, classes: 'ac_bip'
end
column "Signed Up" do |campaign|
if campaign.referred && campaign.referred > 0
raw(AdCampaignsHelper.spacer(campaign.joined, campaign.referred))
else
raw("? - #{campaign.joined}")
end
end
column "Downloaded" do |campaign|
raw(AdCampaignsHelper.spacer(campaign.downloaded, campaign.joined))
end
column "Ran Client" do |campaign|
raw(AdCampaignsHelper.spacer(campaign.ran_client, campaign.joined))
end
column "FTUE" do |campaign|
raw(AdCampaignsHelper.spacer(campaign.ftue, campaign.joined))
end
column "Any Session" do |campaign|
raw(AdCampaignsHelper.spacer(campaign.any_session, campaign.joined))
end
column "2+ Session" do |campaign|
raw(AdCampaignsHelper.spacer(campaign.real_session, campaign.joined))
end
column "Good Session" do |campaign|
raw(AdCampaignsHelper.spacer(campaign.good_session, campaign.joined))
end
column "Invited" do |campaign|
raw(AdCampaignsHelper.spacer(campaign.invited, campaign.joined))
end
column "Friended" do |campaign|
raw(AdCampaignsHelper.spacer(campaign.friended, campaign.joined))
end
column "Platinum" do |campaign|
campaign.platinum
end
column "Gold" do |campaign|
campaign.gold
end
column "Silver" do |campaign|
campaign.silver
end
end
controller do
def scoped_collection
User.select("users.origin_utm_campaign,
users.origin_utm_medium, COUNT(users.id) AS joined,
COUNT(users.first_downloaded_client_at) AS downloaded,
COUNT(users.first_subscribed_at) AS subscribed,
COUNT(users.first_ran_client_at) AS ran_client,
COUNT(users.first_certified_gear_at) AS ftue,
COUNT(users.first_music_session_at) AS any_session,
COUNT(users.first_real_music_session_at) AS real_session,
COUNT(users.first_good_music_session_at) AS good_session,
COUNT(users.first_invited_at) AS invited,
COUNT(users.first_friended_at) AS friended,
COUNT(CASE WHEN users.first_subscribed_plan_code = 'jamsubplatinum' OR users.first_subscribed_plan_code = 'jamsubplatinumyearly' THEN users.first_subscribed_plan_code END) AS platinum,
COUNT(CASE WHEN users.first_subscribed_plan_code = 'jamsubgold' OR users.first_subscribed_plan_code = 'jamsubgoldyearly' THEN users.first_subscribed_plan_code END) AS gold,
COUNT(CASE WHEN users.first_subscribed_plan_code = 'jamsubsilver' OR users.first_subscribed_plan_code = 'jamsubsilveryearly' THEN users.first_subscribed_plan_code END) AS silver,
ad_campaigns.id,
COALESCE(MAX(ad_campaigns.referred), NULL) as referred,
COALESCE(MAX(ad_campaigns.end_date), NULL) AS end_date,
COALESCE(MAX(ad_campaigns.spend), 0) AS spend").joins("
LEFT JOIN ad_campaigns ON users.origin_utm_campaign = ad_campaigns.campaign
AND users.origin_utm_medium = ad_campaigns.medium").where("
users.origin_utm_campaign IS NOT NULL AND users.origin_utm_medium IS NOT NULL AND users.origin_utm_source = 'paid'").group("
ad_campaigns.id, users.origin_utm_campaign, users.origin_utm_medium").order("
users.origin_utm_campaign DESC")
end
def permitted_params
params.permit :campaign, :medium, :_method, ad_campaign: [:spend, :referred, :end_date]
end
end
collection_action :inplace_update, method: :put do
campaign = permitted_params[:campaign]
medium = permitted_params[:medium]
@ad_campaign = JamRuby::AdCampaign.where(campaign: campaign, medium: medium).first_or_create
respond_to do |format|
if @ad_campaign.update_attributes(permitted_params[:ad_campaign])
format.json { head :ok }
else
format.json{ render :json => @ad_campaign.errors.full_messages, :status => :unprocessable_entity }
end
end
end
end

View File

@ -1,43 +0,0 @@
# module AdCampaignsHelper
# def campaign_brought_in_users(campaign, medium)
# User.where(origin_utm_campaign: campaign, origin_utm_medium: medium)
# end
# end
# ActiveAdmin.register JamRuby::AdCampaign do
# permit_params :campaign, :medium, :spend
# end
# ActiveAdmin.register_page "Ad campaigns" do
# menu parent: 'Reports'
# content :title => "Paid Advertising Report" do
# table_for User.select("users.origin_utm_campaign, users.origin_utm_medium, COALESCE(MAX(ad_campaigns.end_date), NULL) AS end_date, COALESCE(MAX(ad_campaigns.spend), NULL) AS spend").joins("LEFT JOIN ad_campaigns ON users.origin_utm_campaign = ad_campaigns.campaign AND users.origin_utm_medium = ad_campaigns.medium").group("ad_campaigns.id, users.origin_utm_campaign, users.origin_utm_medium") do
# column "Campaign" do |campaign|
# campaign.origin_utm_campaign
# end
# column "Medium" do |campaign|
# campaign.origin_utm_medium
# end
# column "End Date" do |campaign|
# campaign.end_date
# end
# column "Hard Date" do |campaign|
# campaign.end_date + 45.days if campaign.end_date.present?
# end
# column "Subscribed" do |campaign|
# end
# column "Spend" do |campaign|
# best_in_place campaign, :spend, as: :input, url: admin_ad_campaigns_update_path(campaign: campaign.origin_utm_campaign, medium: campaign.origin_utm_medium), param: 'ad_campaign'
# end
# end
# end
# page_action :update, method: :put do
# campaign = params[:campaign]
# medium = params[:medium]
# ad_campaign = AdCampaign.where(campaign: campaign, medium: medium).first_or_initialize
# ad_campaign.attributes = params["ad_campaign"]
# ad_campaign.save!
# respond_with_bip(ad_campaign)
# end
# end

View File

@ -1,108 +0,0 @@
class AffiliateCohortsHelper
def self.percentage(opTop, opBottom)
"#{(opTop/opBottom * 100).round(1)}%"
end
def self.quarter(date)
case date.month
when 1, 2, 3 then 0
when 4, 5, 6 then 1
when 7, 8, 9 then 2
when 10, 11, 12 then 3
end
end
def self.payments_for_months(affiliate_partner, year, start_month, end_month)
JamRuby::AffiliateMonthlyPayment.where(
"affiliate_partner_id = ? AND month >= ? AND month <= ? AND year = ?",
affiliate_partner.id,
start_month,
end_month,
year
).order('month DESC')
end
def self.payments_for_quarter(affiliate_partner, year, quarter)
JamRuby::AffiliateQuarterlyPayment.where(
"affiliate_partner_id = ? AND quarter = ? AND year = ?",
affiliate_partner.id,
quarter,
year
).order('quarter DESC')
end
def self.all_time_payments(affiliate_partner)
JamRuby::AffiliateQuarterlyPayment.where(
"affiliate_partner_id = ?", affiliate_partner.id
)
end
def self.current_quarter_payments(affiliate_partner)
AffiliateCohortsHelper.payments_for_quarter(affiliate_partner,
Date.today.year,
AffiliateCohortsHelper.quarter(Date.today)
)
end
def self.current_quarter_monthly_payments(affiliate_partner)
AffiliateCohortsHelper.payments_for_months(affiliate_partner,
Date.today.beginning_of_quarter.year,
Date.today.beginning_of_quarter.month,
Date.today.end_of_quarter.month
)
end
def self.prior_quarter_payments(affiliate_partner)
prev_quarter_start = (Date.today.beginning_of_quarter - 1.day).beginning_of_quarter
prev_quarter = AffiliateCohortsHelper.quarter(prev_quarter_start)
AffiliateCohortsHelper.payments_for_quarter(affiliate_partner,
prev_quarter_start.year,
prev_quarter
)
end
def self.prior_quarter_payable_amount(affiliate_partner)
total = AffiliateCohortsHelper.prior_quarter_payments(affiliate_partner).inject(0.0){ | sum, payment |
sum += payment.due_amount_in_cents }
paid = AffiliateCohortsHelper.prior_quarter_payments(affiliate_partner).where(paid: false).inject(0.0){ | sum, payment |
sum += payment.due_amount_in_cents }
(total - paid) / 100.0
end
end
ActiveAdmin.register_page "Affiliate Cohorts" do
menu parent: 'Reports'
content :title => "Affiliate Cohorts" do
table_for AffiliatePartner.includes(:partner_user).all do
column 'Affiliate Name' do |partner|
link_to partner.partner_name, admin_affiliate_path(partner)
end
column 'Affiliate ID', :id
column 'Affiliate Email', Proc.new{ | partner | partner&.partner_user&.email}
column 'Affiliate Paypal', Proc.new{| partner | partner.paypal_id }
column 'All Time Users', :referral_user_count
column 'All Time Subscribers', Proc.new{ | partner | partner.subscribed_user_referrals.size }
column 'All Time Subscriber Conversion Rate', Proc.new{ | partner |
AffiliateCohortsHelper.percentage(partner.subscribed_user_referrals.size.to_f, partner.referral_user_count.to_f) }
column 'All Time Revenues', Proc.new{ | partner |
number_to_currency(AffiliateCohortsHelper.all_time_payments(partner).inject(0.0){ | sum, payment | sum += payment.due_amount_in_cents } / 100.0)
}
column 'Current Quarter Revenues', Proc.new{ | partner |
number_to_currency(AffiliateCohortsHelper.current_quarter_payments(partner).inject(0.0){ | sum, payment | sum += payment.due_amount_in_cents } / 100.0 )
}
column 'Current Quarter Revenues by Month', Proc.new{ | partner |
AffiliateCohortsHelper.current_quarter_monthly_payments(partner).each do |monthly_payment|
li "#{Date::MONTHNAMES[monthly_payment.month]} #{monthly_payment.year} - #{number_to_currency(monthly_payment.due_amount_in_cents.to_f / 100.0)}"
end
''.html_safe
}
column 'Prior Quarter Revenues', Proc.new{ | partner |
number_to_currency(AffiliateCohortsHelper.prior_quarter_payments(partner).inject(0.0){ | sum, payment | sum += payment.due_amount_in_cents } / 100.0)
}
column 'Prior Quarter Payable', Proc.new{ | partner |
number_to_currency(AffiliateCohortsHelper.prior_quarter_payable_amount(partner))
}
end
end
end

View File

@ -1,33 +0,0 @@
ActiveAdmin.register JamRuby::AffiliateLink, :as => 'Affiliate Links' do
menu :label => 'Links', :parent => 'Affiliates'
config.sort_order = 'created_at ASC'
config.batch_actions = false
# config.clear_action_items!
config.filters = false
config.per_page = 50
config.paginate = true
#form :partial => 'form'
form do |f|
f.inputs 'Fields' do
f.input(:name, :input_html => { :maxlength => 255 })
f.input(:link, :input_html => { :maxlength => 255 })
end
f.actions
end
index do
column 'Name' do |oo|
oo.name
end
column 'Link' do |oo|
oo.link
end
actions
end
end

View File

@ -2,7 +2,7 @@ ActiveAdmin.register JamRuby::AffiliateQuarterlyPayment, :as => 'Affiliate Quart
menu :label => 'Quarterly Reports', :parent => 'Affiliates' menu :label => 'Quarterly Reports', :parent => 'Affiliates'
config.sort_order = 'year desc, quarter desc, due_amount_in_cents desc' config.sort_order = 'due_amount_in_cents DESC'
config.batch_actions = false config.batch_actions = false
config.clear_action_items! config.clear_action_items!
config.filters = true config.filters = true
@ -14,32 +14,18 @@ ActiveAdmin.register JamRuby::AffiliateQuarterlyPayment, :as => 'Affiliate Quart
filter :quarter filter :quarter
filter :closed filter :closed
filter :paid filter :paid
filter :jamtracks_sold
filter :subscriptions_count
filter :due_amount_in_cents
form :partial => 'form' form :partial => 'form'
scope("Sorted By Due Amount", default: true) { |scope| scope.order('year desc, quarter desc, due_amount_in_cents desc') }
scope("Sorted By Jamtracks Sold", default: false) { |scope| scope.order('year desc, quarter desc, jamtracks_sold desc') }
scope("Sorted By Subs", default: false) { |scope| scope.order('year desc, quarter desc, subscriptions_count desc') }
scope("Sorted By Newest First") { |scope| scope.order('year desc, quarter desc, id desc') }
scope("Any") { |scope| scope.order('year desc, quarter desc, due_amount_in_cents desc') }
index do index do
# default_actions # use this for all view/edit/delete links # default_actions # use this for all view/edit/delete links
column 'Year' do |oo| oo.year end column 'Year' do |oo| oo.year end
column 'Quarter' do |oo| oo.quarter end column 'Quarter' do |oo| oo.quarter end
column 'Partner Id' do |oo| oo.affiliate_partner.id end
column 'Partner' do |oo| link_to(oo.affiliate_partner.display_name, oo.affiliate_partner.admin_url, {:title => oo.affiliate_partner.display_name}) end column 'Partner' do |oo| link_to(oo.affiliate_partner.display_name, oo.affiliate_partner.admin_url, {:title => oo.affiliate_partner.display_name}) end
column "Tot ($)" do |oo| sprintf("$%.2f", oo.due_amount_in_cents.to_f / 100.to_f) end column "Due (\u00A2)" do |oo| oo.due_amount_in_cents end
column "Sub ($)" do |oo| sprintf("$%.2f", oo.subscription_due_amount_in_cents.to_f / 100.to_f) end column 'JamTracks Sold' do |oo| oo.jamtracks_sold end
column "Jam ($)" do |oo| sprintf("$%.2f", oo.jamtrack_due_amount_in_cents.to_f / 100.to_f) end
column 'JamTracks' do |oo| oo.jamtracks_sold end
column 'Subscriptions' do |oo| oo.subscriptions_count end
column 'Paid' do |oo| oo.paid end column 'Paid' do |oo| oo.paid end
column 'Closed' do |oo| oo.paid end column 'Closed' do |oo| oo.paid end

View File

@ -23,9 +23,7 @@ ActiveAdmin.register JamRuby::AffiliateTrafficTotal, :as => 'Affiliate Daily Sta
# default_actions # use this for all view/edit/delete links # default_actions # use this for all view/edit/delete links
column 'Day' do |oo| oo.day end column 'Day' do |oo| oo.day end
column 'Partner ID' do |oo| oo.affiliate_partner.id end column 'Partner' do |oo| link_to(oo.affiliate_partner.display_name, oo.affiliate_partner.admin_url, {:title => oo.affiliate_partner.display_name}) end
column 'Partner Name' do |oo| oo.affiliate_partner.display_name end
column 'Partner User' do |oo| link_to(oo.affiliate_partner.partner_user.name, admin_user_path(oo.affiliate_partner.partner_user.id), { :title => oo.affiliate_partner.partner_user.name }) end
column 'Signups' do |oo| oo.signups end column 'Signups' do |oo| oo.signups end
column 'Visits' do |oo| oo.visits end column 'Visits' do |oo| oo.visits end
@ -33,16 +31,6 @@ ActiveAdmin.register JamRuby::AffiliateTrafficTotal, :as => 'Affiliate Daily Sta
controller do controller do
def scoped_collection
rel = end_of_association_chain
.includes([:affiliate_partner])
.order('day DESC')
if (ref_id = params[AffiliatePartner::PARAM_REFERRAL]).present?
qq = ['affiliate_partner_id = ?', ref_id]
else
qq = ['affiliate_partner_id IS NOT NULL']
end
@users ||= rel.where(qq)
end
end end
end end

View File

@ -8,32 +8,27 @@ ActiveAdmin.register JamRuby::User, :as => 'Referrals' do
config.filters = true config.filters = true
filter :affiliate_referral filter :affiliate_referral
filter :email
## scope("Has Signups", default: true) { |scope| scope.where('visits != 0 or signups != 0').order('day desc') }
index do index do
column 'User' do |oo| link_to(oo.name, oo.admin_url, {:title => oo.name}) end column 'User' do |oo| link_to(oo.name, oo.admin_url, {:title => oo.name}) end
column 'User Email' do |oo| oo.email end column 'Email' do |oo| oo.email end
column 'Created' do |oo| oo.created_at end column 'Created' do |oo| oo.created_at end
column 'Partner ID' do |oo| oo.affiliate_referral.id end column 'Partner' do |oo| oo.affiliate_referral.display_name end
column 'Partner Name' do |oo| oo.affiliate_referral.display_name end
column 'Partner User' do |oo| link_to(oo.affiliate_referral.partner_user.name, admin_user_path(oo.affiliate_referral.partner_user.id), { :title => oo.affiliate_referral.partner_user.name }) end
end end
controller do controller do
def scoped_collection def scoped_collection
rel = end_of_association_chain rel = end_of_association_chain
.includes([:affiliate_referral]) .includes([:affiliate_referral])
.order('created_at DESC') .order('created_at DESC')
if (ref_id = params[AffiliatePartner::PARAM_REFERRAL]).present? if (ref_id = params[AffiliatePartner::PARAM_REFERRAL]).present?
qq = ['affiliate_referral_id = ?', ref_id] qq = ['affiliate_referral_id = ?', ref_id]
else else
qq = ['affiliate_referral_id IS NOT NULL'] qq = ['affiliate_referral_id IS NOT NULL']
end
@users ||= rel.where(qq)
end end
@users ||= rel.where(qq)
end
end end
end end

View File

@ -5,104 +5,26 @@ ActiveAdmin.register JamRuby::AffiliatePartner, :as => 'Affiliates' do
config.sort_order = 'referral_user_count DESC' config.sort_order = 'referral_user_count DESC'
config.batch_actions = false config.batch_actions = false
# config.clear_action_items! # config.clear_action_items!
config.filters = true config.filters = false
config.per_page = 100 config.per_page = 50
config.paginate = true config.paginate = true
#form :partial => 'form' form :partial => 'form'
scope("Active", default: true) { |scope| scope.where('partner_user_id IS NOT NULL').order('referral_user_count desc') }
#filter :partner_user
filter :partner_name
filter :id
filter :current_quarter_in_cents
filter :cumulative_earnings_in_cents
filter :jamtracks_sold
filter :subscriptions_count
filter :referral_user_count
scope("Sorted By Current Quarter", default: true) { |scope| scope.where('partner_user_id IS NOT NULL').order('current_quarter_in_cents desc') }
scope("Sorted By Jamtracks Sold", default: false) { |scope| scope.where('partner_user_id IS NOT NULL').order('jamtracks_sold desc') }
scope("Sorted By Subs", default: false) { |scope| scope.where('partner_user_id IS NOT NULL').order('subscriptions_count desc') }
scope("Sorted By Signups", default: false) { |scope| scope.where('partner_user_id IS NOT NULL').order('referral_user_count desc') }
scope("Sorted By Newest First") { |scope| scope.where('partner_user_id IS NOT NULL').order('id desc') }
scope("Any") { |scope| scope.where('partner_user_id IS NOT NULL').order('referral_user_count desc') }
scope("Unpaid") { |partner| partner.unpaid } scope("Unpaid") { |partner| partner.unpaid }
controller do
helper 'active_admin/subscription'
end
form do |f|
f.inputs 'Fields' do
f.input(:partner_name, :input_html => { :maxlength => 128 })
f.input(:partner_user, as: :searchable_select, hint: 'This person is the owner of the affiliate. Has access to reporting info in account section of www.jamkazam.com')
f.input(:entity_type, :as => :select, :collection => AffiliatePartner::ENTITY_TYPES)
f.input(:rate)
f.input(:paypal_id)
end
f.actions
end
index do index do
# actions # use this for all view/edit/delete links # actions # use this for all view/edit/delete links
column 'User' do |oo| column 'User' do |oo| link_to(oo.partner_user.name, admin_user_path(oo.partner_user.id), {:title => oo.partner_user.name}) end
link_to(oo.partner_user.name, admin_user_path(oo.partner_user.id), { :title => oo.partner_user.name }) column 'Name' do |oo| oo.partner_name end
end column 'Type' do |oo| oo.entity_type end
column 'Name' do |oo| column 'Code' do |oo| oo.id end
oo.partner_name column 'Referral Count' do |oo| oo.referral_user_count end
end column 'Earnings' do |oo| sprintf("$%.2f", oo.cumulative_earnings_in_dollars) end
column 'Type' do |oo| column 'Amount Owed' do |oo| sprintf("$%.2f", oo.due_amount_in_cents.to_f / 100.to_f) end
oo.entity_type
end
column 'Code' do |oo|
oo.id
end
column 'Signups' do |oo|
oo.referral_user_count
end
column 'JamTracks' do |oo|
oo.jamtracks_sold
end
column 'Subs' do |oo|
oo.subscriptions_count
end
column 'Cum Earnings' do |oo|
div do
sprintf("Tot $%.2f", oo.cumulative_earnings_in_dollars)
end
div do
sprintf("Jam $%.2f", oo.jamtrack_cumulative_earnings_in_dollars)
end
div do
sprintf("Sub $%.2f", oo.subscriptions_cumulative_earnings_in_dollars)
end
end
column 'Current Quarter' do |oo|
div do
sprintf("Tot $%.2f", oo.current_quarter_in_dollars)
end
div do
sprintf("Jam $%.2f", oo.jamtrack_current_quarter_in_dollars)
end
div do
sprintf("Sub $%.2f", oo.subscriptions_current_quarter_in_dollars)
end
end
column 'Amount Owed' do |oo|
div do
sprintf("Tot $%.2f", oo.due_amount_in_cents.to_f / 100.to_f)
end
div do
sprintf("Jam $%.2f", oo.jamtrack_due_amount_in_cents.to_f / 100.to_f)
end
div do
sprintf("Sub $%.2f", oo.subscription_due_amount_in_cents.to_f / 100.to_f)
end
end
column 'Pay Actions' do |oo| column 'Pay Actions' do |oo|
link_to('Mark Paid', mark_paid_admin_affiliate_path(oo.id), :confirm => "Mark this affiliate as PAID?") if oo.unpaid link_to('Mark Paid', mark_paid_admin_affiliate_path(oo.id), :confirm => "Mark this affiliate as PAID?") if oo.unpaid
end end
@ -110,31 +32,6 @@ ActiveAdmin.register JamRuby::AffiliatePartner, :as => 'Affiliates' do
actions actions
end end
show do |affiliate_partner|
attributes_table do
row :id
row :partner_name
row :entity_type
row :rate
row :address
row :tax_identifier
row :paypal_id
row :venmo_user_id
row :jamtracks_sold
row :subscriptions_count
row :cumulative_earnings_in_dollars
row :jamtrack_cumulative_earnings_in_dollars
row :subscriptions_cumulative_earnings_in_dollars
row :current_quarter_in_dollars
row :jamtrack_current_quarter_in_dollars
row :subscriptions_current_quarter_in_dollars
end
render 'earnings', { affiliate_partner: affiliate_partner }
end
action_item :only => [:show] do action_item :only => [:show] do
link_to("Mark Paid", link_to("Mark Paid",

View File

@ -1,21 +0,0 @@
ActiveAdmin.register JamRuby::AppFeature, as: 'App Features' do
menu parent: 'Misc', label: 'App Features'
config.sort_order = 'created_at ASC'
config.batch_actions = false
config.filters = false
config.per_page = 50
config.paginate = true
form do |f|
f.inputs 'Fields' do
f.input(:feature_type, as: :select, collection: JamRuby::AppFeature::FEATURE_TYPES)
f.input(:handle, :input_html => { :maxlength => 1025 })
f.input(:is_enabled, as: :boolean)
f.input(:env, as: :select, collection: %w(production staging development))
end
f.actions
end
end

View File

@ -3,7 +3,7 @@ ActiveAdmin.register JamRuby::GenericState, :as => 'GenericState' do
config.clear_action_items! config.clear_action_items!
filter :env filter :env
permit_params :top_message, :event_page_top_logo_url, :customer_ltv, :connection_policy permit_params :top_message, :event_page_top_logo_url, :connection_policy
actions :all, :except => [:destroy] actions :all, :except => [:destroy]

View File

@ -1,11 +1,5 @@
ActiveAdmin.register JamRuby::User, :as => 'Users' do ActiveAdmin.register JamRuby::User, :as => 'Users' do
searchable_select_options(scope: User.all,
text_attribute: :username,
filter: lambda do |term, scope|
scope.ransack(full_name_or_email_cont: term).result
end)
collection_action :autocomplete_user_email, :method => :get collection_action :autocomplete_user_email, :method => :get
actions :all, :except => [:destroy] actions :all, :except => [:destroy]
@ -23,116 +17,6 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
form :partial => "form" form :partial => "form"
action_item :school_user, only: :index do
link_to "Quick Add School User", add_school_user_admin_users_path
end
action_item :latency, only: :show do
link_to 'Show Latency', latency_admin_user_path(resource)
end
collection_action :add_school_user, method: [:get, :post] do
if request.post?
@client = RecurlyClient.new
errors = []
user_params = params[:jam_ruby_user]
user_type = user_params[:user_type].strip
school_id = user_params[:school_id].strip
return (render text: "Please select school") if school_id.blank?
first_name = user_params[:first_name].strip
last_name = user_params[:last_name].strip
email = user_params[:email].strip.downcase
license_start = user_params[:license_start].strip
license_end = user_params[:license_end].strip
import_source = user_params[:import_source].strip
password = SecureRandom.uuid
options = {
first_name: first_name,
last_name: last_name,
email: email,
license_start: license_start,
license_end: license_end,
import_source: import_source,
terms_of_service: true,
musician: true,
skip_recaptcha: true,
password: password,
password_confirmation: password
}
options.merge!({ school_id: school_id }) if school_id.present?
instrument = Instrument.find('electric guitar')
instruments = [{instrument_id: instrument.id, proficiency_level: 3, priority: 1}]
options[:instruments] = instruments
parse_user_type(user_type, options)
@user = User.find_by_email(options[:email])
unless @user.nil?
@user.user_type = user_type
#if @user.import_source.nil?
#TODO: do we need to have following 3 lines for an existing user?
@user.import_source = options[:import_source]
@user.license_start = options[:license_start]
@user.license_end = options[:license_end]
if options[:student]
@user.school_id = options[:school_id]
@user.is_a_student = true
elsif options[:teacher]
@user.school = school
if @user.teacher.nil?
@user.teacher = Teacher.build_teacher(@user, validate_introduction: true, biography: "Empty biography", school_id: school.id)
end
elsif options[:platform_instructor]
@user.is_platform_instructor = true
end
if @user.save
@client.sync_subscription(@user)
if options[:student]
UserMailer.school_welcome_message(@user, nil).deliver_now
elsif options[:teacher]
UserMailer.school_welcome_message(@user, nil).deliver_now
elsif options[:platform_instructor]
end
end
if @user.errors.any?
flash[:error] = "Error updating User #{@user.name} #{@user.email}"
render :add_school_user
else
flash[:notice] = "User #{@user.name} #{@user.email} updated successfully"
redirect_to admin_users_path
end
#end
else
@user = User.signup(options)
if @user.errors.none?
@client.sync_subscription(@user)
puts "User #{@user.email} created"
flash[:notice] = "User #{@user.name} #{@user.email} added successfully"
redirect_to admin_users_path
else
flash[:error] = "Error adding school user"
render :add_school_user
end
end
else
@user = User.new
@user.import_source = 'Manual'
end
end
member_action :update_school_user, method: [:get, :put] do
end
member_action :delete_forever, :method => :get do member_action :delete_forever, :method => :get do
resource.permanently_delete resource.permanently_delete
redirect_to :back, {notice: 'User email and login credentials have been permanently changed'} redirect_to :back, {notice: 'User email and login credentials have been permanently changed'}
@ -190,12 +74,6 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
redirect_to :back, {notice: "Check the Subscription Plan Code, Subscription Sync Code, Subscription Sync Msg"} redirect_to :back, {notice: "Check the Subscription Plan Code, Subscription Sync Code, Subscription Sync Msg"}
end end
member_action :reset_monthly_play, :method => :get do
resource.used_month_play_time = 0
resource.save!
redirect_to :back, {notice: "Reset user's monthly play time to 0"}
end
member_action :change_to_plan, :method => :get do member_action :change_to_plan, :method => :get do
@client = RecurlyClient.new @client = RecurlyClient.new
plan_code = params[:plan_code] plan_code = params[:plan_code]
@ -230,28 +108,7 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
end end
member_action :latency, method: :get do
@user = resource
latency_url = "#{Rails.application.config.latency_data_host}/user/#{@user.id}"
uri = URI(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://")
req = Net::HTTP::Get.new(uri.request_uri)
req["Authorization"] = "Basic #{Rails.application.config.latency_data_host_auth_code}"
req["Content-Type"] = "application/json"
response = http.request(req)
render text: "404 Not Found", status: 404 if response.is_a?(Net::HTTPNotFound)
#render json: response.body, status: 200 if response.is_a?(Net::HTTPOK) || response.is_a?(Net::HTTPSuccess)
@user_latency = response.body
rescue => e
render text: e.message
end
end
show do |user| show do |user|
panel "Common" do panel "Common" do
@ -271,7 +128,6 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
row :gender row :gender
row :email_confirmed row :email_confirmed
row :remember_token row :remember_token
=begin
row "Session Ready" do |user| row "Session Ready" do |user|
div do div do
if user.ready_for_session_at if user.ready_for_session_at
@ -298,7 +154,6 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
end end
end end
end end
=end
row "Delete Forever" do |user| row "Delete Forever" do |user|
span do span do
link_to("delete forever", delete_forever_admin_user_path(user.id), :data => {:confirm => 'Are you sure?'}) link_to("delete forever", delete_forever_admin_user_path(user.id), :data => {:confirm => 'Are you sure?'})
@ -346,24 +201,6 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
row :subscription_sync_msg row :subscription_sync_msg
row :is_past_due row :is_past_due
row :stored_credit_card row :stored_credit_card
row "Monthly Time Used" do |user|
div do
remaining_month_play_time = user.subscription_rules[:remaining_month_play_time]
if remaining_month_play_time.nil?
span do
"No limit"
end
elsif user.played_this_month?
span do
"Used: #{user.used_month_play_time / 60} min | Remaining #{remaining_month_play_time / 60} min"
end
else
span do
"Did not play this month. Last played #{user.used_current_month}"
end
end
end
end
end end
end end
div do div do
@ -388,44 +225,25 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
'sets secret override to give user a free plan (link goes to another page)' 'sets secret override to give user a free plan (link goes to another page)'
end end
div do div do
link_to("give no-payment plan", edit_admin_user_override_path(user.id)) link_to("Give No-Payment Plan", edit_admin_subscription_path(user.id))
end
end
div do
h3 do
'Reset Monthly Play Time'
end
h4 do
'sets the user\'s monthly play time to 0'
end
div do
link_to("reset monthly play time", reset_monthly_play_admin_user_path(user.id), :data => {:confirm => 'Are you sure?'})
end end
end end
div do div do
h3 do h3 do
'Change Plan Actions' 'Change Plan Actions'
end end
h4 do h4 do
'Change desired plan exactly as if the user did it on /client#/accounts/subscription' 'Change desired plan xactly as if the user did it on /client#/accounts/subscription'
end end
div do div do
link_to("change plan to silver monthly", change_to_plan_admin_user_path(user.id, plan_code: 'jamsubsilver'), :data => {:confirm => 'Are you sure?'}) link_to("change plan to silver", change_to_plan_admin_user_path(user.id, 'jamsubsilver'), :data => {:confirm => 'Are you sure?'})
end end
div do div do
link_to("change plan to gold monthly", change_to_plan_admin_user_path(user.id, plan_code: 'jamsubgold'), :data => {:confirm => 'Are you sure?'}) link_to("change plan to gold", change_to_plan_admin_user_path(user.id, plan_code: 'jamsubgold'), :data => {:confirm => 'Are you sure?'})
end end
div do div do
link_to("change plan to platinum monthly", change_to_plan_admin_user_path(user.id, plan_code: 'jamsubplatinum'), :data => {:confirm => 'Are you sure?'}) link_to("change plan to platinum", change_to_plan_admin_user_path(user.id, plan_code: 'jamsubplatinum'), :data => {:confirm => 'Are you sure?'})
end
div do
link_to("change plan to silver yearly", change_to_plan_admin_user_path(user.id, plan_code: 'jamsubsilveryearly'), :data => {:confirm => 'Are you sure?'})
end
div do
link_to("change plan to gold yearly", change_to_plan_admin_user_path(user.id, plan_code: 'jamsubgoldyearly'), :data => {:confirm => 'Are you sure?'})
end
div do
link_to("change plan to platinum yearly", change_to_plan_admin_user_path(user.id, plan_code: 'jamsubplatinumyearly'), :data => {:confirm => 'Are you sure?'})
end end
div do div do
link_to("change plan to free", change_to_plan_admin_user_path(user.id, plan_code: ''), :data => {:confirm => 'Are you sure?'}) link_to("change plan to free", change_to_plan_admin_user_path(user.id, plan_code: ''), :data => {:confirm => 'Are you sure?'})
@ -475,56 +293,35 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
end end
end end
panel "Onboarding" do
panel "School" do attributes_table do
div do row :onboarding_status
attributes_table do row "Support Consultant" do |user|
row "School" do |user| if user.onboarder
span do link_to "#{user.onboarder.name} (#{user.onboarder.onboarding_users.count})", user.onboarder.admin_url
if user.school else
link_to user.school.name, admin_school_path(user.school), target: '_blank'
end
end
end
if user.school
row :license_start
row :license_end
row :is_platform_instructor
end end
end 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
row "Email 3", :onboarding_email_3_sent_at
row "Email 4", :onboarding_email_4_sent_at
row "Email 5", :onboarding_email_5_sent_at
row "Test Session Scheduled Time", :onboarding_test_session_at
row "When Test Session Was Requested", :onboarding_test_session_at
row "Test Session Outcome", :onboarding_test_session_outcome
row "Notes", :onboarding_onboarder_notes
row "Lost Reason", :onboarding_lost_reason
row "Lost At", :onboarding_lost_at
row "Escalated Reason", :onboarding_escalation_reason
row "Escalated At", :onboarding_escalated_at
end end
end end
# panel "Onboarding" do
# attributes_table do
# row :onboarding_status
# row "Support Consultant" do |user|
# if user.onboarder
# link_to "#{user.onboarder.name} (#{user.onboarder.onboarding_users.count})", user.onboarder.admin_url
# else
# end
# 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
# row "Email 3", :onboarding_email_3_sent_at
# row "Email 4", :onboarding_email_4_sent_at
# row "Email 5", :onboarding_email_5_sent_at
# row "Test Session Scheduled Time", :onboarding_test_session_at
# row "When Test Session Was Requested", :onboarding_test_session_at
# row "Test Session Outcome", :onboarding_test_session_outcome
# row "Notes", :onboarding_onboarder_notes
# row "Lost Reason", :onboarding_lost_reason
# row "Lost At", :onboarding_lost_at
# row "Escalated Reason", :onboarding_escalation_reason
# row "Escalated At", :onboarding_escalated_at
# end
# end
=begin
panel "Teacher Setting" do panel "Teacher Setting" do
attributes_table do attributes_table do
@ -590,8 +387,6 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
end end
=end
panel "JamTracks" do panel "JamTracks" do
div do div do
link_to "Give JamTrack", "../jam_track_rights/new" link_to "Give JamTrack", "../jam_track_rights/new"
@ -621,31 +416,32 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
links << link_to("Edit", edit_resource_path(user), :class => "member_link edit_link") links << link_to("Edit", edit_resource_path(user), :class => "member_link edit_link")
links links
end end
column "ID" do |user|
link_to(truncate(user.id, {:length => 12}),
resource_path(user),
{:title => user.id})
end
column "Email" do |user| column "Email" do |user|
link_to user.email, resource_path(user) link_to user.email, resource_path(user)
end end
column :subscription_plan_code column :admin
column :desired_plan_code
column :created_at column :created_at
column :first_name column :musician do |user|
column :last_name user.musician? ? true : false
end
column :city column :city
column :state column :state
column :first_name
column :last_name
end end
controller do controller do
# this actually searches on first name, last name, and email, because of get_autocomplete_items defined below # this actually searches on first name, last name, and email, because of get_autocomplete_items defined below
autocomplete :user, :email, :full => true, :display_value => :autocomplete_display_name, extra_data: [:last_jam_addr] autocomplete :user, :email, :full => true, :display_value => :autocomplete_display_name
def get_autocomplete_items(parameters) def get_autocomplete_items(parameters)
term = parameters[:term] User.select("email, first_name, last_name, id").where(["email ILIKE ? OR first_name ILIKE ? OR last_name ILIKE ?", "%#{parameters[:term]}%", "%#{parameters[:term]}%", "%#{parameters[:term]}%"])
if term.include?('@')
User.select("email, first_name, last_name, id, last_jam_addr").where(["email = ?", term]).limit(5)
else
User.select("email, first_name, last_name, id, last_jam_addr").where(["email ILIKE ? OR first_name ILIKE ? OR last_name ILIKE ?", "%#{term}%", "%#{term}%", "%#{term}%"]).limit(40)
end
end end
@ -667,6 +463,7 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
@user = resource @user = resource
@user.email = params[:jam_ruby_user][:email] @user.email = params[:jam_ruby_user][:email]
@user.admin = params[:jam_ruby_user][:admin] @user.admin = params[:jam_ruby_user][:admin]
@user.is_onboarder = params[:jam_ruby_user][:is_onboarder]
@user.subscribe_email = params[:jam_ruby_user][:subscribe_email] @user.subscribe_email = params[:jam_ruby_user][:subscribe_email]
@user.musician = params[:jam_ruby_user][:musician] @user.musician = params[:jam_ruby_user][:musician]
@user.first_name = params[:jam_ruby_user][:first_name] @user.first_name = params[:jam_ruby_user][:first_name]
@ -703,97 +500,6 @@ ActiveAdmin.register JamRuby::User, :as => 'Users' do
redirect_to edit_admin_user_path(@user) redirect_to edit_admin_user_path(@user)
end end
def user_latency_recommendation
recommendation_params = params[:latency_recommendation]
offset = recommendation_params[:offset].blank?? 0 : recommendation_params[:offset]
limit = recommendation_params[:limit].blank?? 20 : recommendation_params[:limit]
is_valid = [
recommendation_params[:my_user_id],
recommendation_params[:my_public_ip]
].all?{ |param|
param.present?
}
if is_valid
instruments = []
instruments << recommendation_params[:instruments_beginner].reject(&:blank?).map{|i| { id: i, proficiency: 1} }
instruments << recommendation_params[:instruments_advanced].reject(&:blank?).map{|i| { id: i, proficiency: 2} }
instruments << recommendation_params[:instruments_expert].reject(&:blank?).map{|i| { id: i, proficiency: 3} }
instruments.flatten!
genres = recommendation_params[:genres].reject(&:blank?)
wifi = recommendation_params[:wifi]
max_latency = recommendation_params[:max_latency]
data = {
my_user_id: recommendation_params[:my_user_id],
my_public_ip: recommendation_params[:my_public_ip],
offset: offset,
limit: limit
}
data.merge!({query: recommendation_params[:query]}) unless recommendation_params[:query].blank?
data.merge!({instruments: instruments}) unless instruments.empty?
data.merge!({genres: genres}) unless genres.empty?
data.merge!({wifi: wifi}) if %w(true false).include?(wifi)
data.merge!({max_latency: max_latency}) unless max_latency.blank?
latency_url = "#{Rails.application.config.latency_data_host}/recommendations"
uri = URI(latency_url)
begin
http = Net::HTTP.new(uri.host, uri.port)
http.read_timeout = 5
http.use_ssl = true if Rails.application.config.latency_data_host.start_with?("https://")
request = Net::HTTP::Post.new(uri.path, 'Content-Type' => 'application/json')
request.body = data.to_json
request["Authorization"] = "Basic #{Rails.application.config.latency_data_host_auth_code}"
response = http.request(request)
@latency_recommendation = response.body
rescue => exception
render text: exception.message
end
else
flash[:error] = 'Please provide all required fields'
redirect_to admin_latency_recommendation_path
end
end
def user_latencies
latency_params = params[:latencies]
latency_url = "#{Rails.application.config.latency_data_host}/user_latencies"
uri = URI(latency_url)
if not ([latency_params[:my_user_id], latency_params[:my_public_ip], latency_params[:user_1_id]]).any?{|param| param.blank? }
user_ids = [latency_params[:user_1_id]]
user_ids.push(latency_params[:user_2_id]) unless latency_params[:user_2_id].blank?
user_ids.push(latency_params[:user_3_id]) unless latency_params[:user_3_id].blank?
user_ids.push(latency_params[:user_4_id]) unless latency_params[:user_4_id].blank?
user_ids.push(latency_params[:user_5_id]) unless latency_params[:user_5_id].blank?
begin
http = Net::HTTP.new(uri.host, uri.port)
http.read_timeout = 5
http.use_ssl = true if Rails.application.config.latency_data_host.start_with?("https://")
request = Net::HTTP::Post.new(uri.path, 'Content-Type' => 'application/json')
request.body = {
my_user_id: latency_params[:my_user_id],
my_public_ip: latency_params[:my_public_ip],
users: user_ids
}.to_json
request["Authorization"] = "Basic #{Rails.application.config.latency_data_host_auth_code}"
response = http.request(request)
@user_latencies = response.body
#render text: JSON.pretty_generate(@user_latencies)
rescue => e
render text: e.message
end
else
flash[:error] = 'Please provide all required fields'
redirect_to admin_latency_between_users_path
end
end
end end
end end

View File

@ -17,14 +17,6 @@ ActiveAdmin.register JamRuby::JamTrackRight, :as => 'JamTrackRights' do
filter :jam_track filter :jam_track
controller do
def create
jt_params = params[:jam_ruby_jam_track_right]
jt_params[:jam_track] =JamRuby::JamTrack.where("id=?", jt_params[:jam_track_id_val]).first # jt_params[:jam_track_id_val]
jt_params[:user] = JamRuby::User.where("id=?", jt_params[:user_id_val]).first # jt_params[:user_id_val]
create!
end
end
index do index do
actions actions
@ -55,14 +47,9 @@ ActiveAdmin.register JamRuby::JamTrackRight, :as => 'JamTrackRights' do
form do |f| form do |f|
f.inputs 'New Jam Track Right' do f.inputs 'New Jam Track Right' do
#f.input :jam_track, :required=>true, collection: JamTrack.all, include_blank: false f.input :jam_track, :required=>true, collection: JamTrack.all, include_blank: false
f.input :jam_track_id_val, :required=>true, :as => :hidden f.input :user, :required=>true, collection: User.all, include_blank: false
f.input :can_download, :required => true, as: :boolean
f.input :jam_track, :required=>true, :as => :autocomplete, :url => autocomplete_jam_track_name_admin_jam_tracks_path, hint: 'Select a jamtrack to give to this user'
#f.input :user, :required=>true, collection: User.all, include_blank: false
f.input :user_id_val, :required=>true, :as => :hidden
f.input :user, :required=>true, :as => :autocomplete, :url => autocomplete_user_email_admin_users_path, hint: 'Give a free jamtrack to this user'
f.input :can_download, :required => true, as: :boolean, :input_html => { :checked => 'checked' }
end end
f.actions f.actions
end end

View File

@ -1,7 +1,5 @@
ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do
collection_action :autocomplete_jam_track_name, :method => :get
menu :label => 'JamTracks', :parent => 'JamTracks' menu :label => 'JamTracks', :parent => 'JamTracks'
config.sort_order = 'name_asc' config.sort_order = 'name_asc'
@ -21,19 +19,6 @@ ActiveAdmin.register JamRuby::JamTrack, :as => 'JamTracks' do
form :partial => 'form' form :partial => 'form'
controller do
# this actually searches on first name, last name, and email, because of get_autocomplete_items defined below
autocomplete :jam_track, :name, :full => true, :display_value => :autocomplete_display_name
def get_autocomplete_items(parameters)
JamTrack.select("name, original_artist, id").where(["name ILIKE ? OR original_artist ILIKE ?", "%#{parameters[:term]}%", "%#{parameters[:term]}%"])
end
end
index do index do
# actions # use this for all view/edit/delete links # actions # use this for all view/edit/delete links

View File

@ -1,185 +0,0 @@
class Spacer
def self.spacer(val, row)
percentage = ((val * 100) / row.total.to_f).round(1).to_s
('%-5.5s' % percentage).gsub(' ', '&nbsp;') + '%&nbsp;-&nbsp;' + val.to_s
end
end
=begin
select
count(id) as total,
count(first_downloaded_client_at) as downloaded,
count(first_ran_client_at) as ran_client,
count(first_certified_gear_at) as ftue,
count(first_music_session_at) as any_session,
count(first_real_music_session_at) as real_session,
count(first_good_music_session_at) as good_session,
count(first_invited_at) as invited,
count(first_friended_at) as friended,
count(first_subscribed_at) as subscribed
from users where users.created_at >= '2024-11-01' AND users.created_at < '2025-04-01'
select first_name, last_name, email
from users where users.created_at >= '2024-11-01' AND users.created_at < '2025-04-01'
AND first_music_session_at is NULL;
=end
ActiveAdmin.register_page "Jammers Subscription Cohorts" do
menu :parent => 'Reports'
content :title => "Jammers Subscription Cohorts" do
filter_type = params[:filter_type] || 'All'
filter_campaign = params[:filter_campaign]
filter_campaign_id = params[:filter_campaign_id]
filter_ad_set = params[:filter_ad_set]
filter_ad_name = params[:filter_ad_name]
campaigns = User.where("origin_utm_medium = 'cpc'").distinct.pluck(:origin_utm_campaign).compact.sort
campaign_ids = User.where("origin_utm_medium = 'cpc'").distinct.pluck(:origin_id).compact.sort
ad_sets = User.where("origin_utm_medium = 'cpc'").distinct.pluck(:origin_term).compact.sort
ad_names = User.where("origin_utm_medium = 'cpc'").distinct.pluck(:origin_content).compact.sort
div style: "margin-bottom: 20px; padding: 10px; background-color: #f4f4f4; border-radius: 4px;" do
form action: admin_jammers_subscription_cohorts_path, method: :get do
span "Source: ", style: "font-weight: bold; margin-right: 5px;"
select name: 'filter_type', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
option "All", value: 'All', selected: filter_type == 'All'
option "Organic", value: 'Organic', selected: filter_type == 'Organic'
option "Advertising", value: 'Advertising', selected: filter_type == 'Advertising'
end
if filter_type == 'Advertising'
div style: "margin-top: 10px;" do
span "Campaign Name: ", style: "font-weight: bold; margin-right: 5px;"
select name: 'filter_campaign', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
option "All", value: ''
option "Null", value: 'NULL', selected: filter_campaign == 'NULL'
campaigns.each do |c|
option c, value: c, selected: filter_campaign == c
end
end
end
div style: "margin-top: 10px;" do
span "Campaign ID: ", style: "font-weight: bold; margin-right: 5px;"
select name: 'filter_campaign_id', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
option "All", value: ''
option "Null", value: 'NULL', selected: filter_campaign_id == 'NULL'
campaign_ids.each do |c|
option c, value: c, selected: filter_campaign_id == c
end
end
end
div style: "margin-top: 10px;" do
span "Ad Set: ", style: "font-weight: bold; margin-right: 5px;"
select name: 'filter_ad_set', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
option "All", value: ''
option "Null", value: 'NULL', selected: filter_ad_set == 'NULL'
ad_sets.each do |c|
option c, value: c, selected: filter_ad_set == c
end
end
div style: "margin-top: 10px;" do
span "Ad Name: ", style: "font-weight: bold; margin-right: 5px;"
select name: 'filter_ad_name', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
option "All", value: ''
option "Null", value: 'NULL', selected: filter_ad_name == 'NULL'
ad_names.each do |c|
option c, value: c, selected: filter_ad_name == c
end
end
end
end
end
noscript { input type: :submit, value: "Filter" }
end
end
h2 "Users Grouped By Month as Paying Subscribers"
query = User.select(%Q{date_trunc('month', users.created_at) as month,
count(id) as total,
count(first_downloaded_client_at) as downloaded,
count(first_ran_client_at) as ran_client,
count(first_certified_gear_at) as ftue,
count(first_music_session_at) as any_session,
count(first_real_music_session_at) as real_session,
count(first_good_music_session_at) as good_session,
count(first_invited_at) as invited,
count(first_friended_at) as friended,
count(first_subscribed_at) as subscribed,
count(first_played_jamtrack_at) as played_jamtrack
})
.joins(%Q{LEFT JOIN LATERAL (
SELECT
j.created_at
FROM
jam_track_rights as j
WHERE
j.user_id = users.id
ORDER BY
j.created_at
LIMIT 1 -- Select only that single row
) j ON TRUE })
if filter_type == 'Organic'
query = query.where("users.origin_utm_source = 'organic'")
elsif filter_type == 'Advertising'
query = query.where("origin_utm_medium = 'cpc'")
if filter_campaign.present?
if filter_campaign == 'NULL'
query = query.where("users.origin_utm_campaign IS NULL")
elsif filter_campaign != 'All'
query = query.where("users.origin_utm_campaign = ?", filter_campaign)
end
end
if filter_campaign_id.present?
if filter_campaign_id == 'NULL'
query = query.where("users.origin_id IS NULL")
elsif filter_campaign_id != 'All'
query = query.where("users.origin_id = ?", filter_campaign_id)
end
end
if filter_ad_set.present?
if filter_ad_set == 'NULL'
query = query.where("users.origin_term IS NULL")
elsif filter_ad_set != 'All'
query = query.where("users.origin_term = ?", filter_ad_set)
end
end
if filter_ad_name.present?
if filter_ad_name == 'NULL'
query = query.where("users.origin_content IS NULL")
elsif filter_ad_name != 'All'
query = query.where("users.origin_content = ?", filter_ad_name)
end
end
end
table_for query.group("date_trunc('month', users.created_at)")
.where("j.created_at IS NULL OR (j.created_at - users.created_at) >= INTERVAL '2 hours'")
.order("date_trunc('month', users.created_at) DESC") do |row|
column "Month", Proc.new { |user| user.month.strftime('%B %Y') }
column "Total", :total
column "Subscribed", Proc.new { |user| raw(Spacer.spacer(user.subscribed, user)) }
column "Downloaded", Proc.new { |user| raw(Spacer.spacer(user.downloaded, user)) }
column "Ran Client", Proc.new { |user| raw(Spacer.spacer(user.ran_client, user)) }
column "FTUE", Proc.new { |user| raw(Spacer.spacer(user.ftue, user)) }
column "Any Session", Proc.new { |user| raw(Spacer.spacer(user.any_session, user)) }
column "2+ Session", Proc.new { |user| raw(Spacer.spacer(user.real_session, user)) }
column "Good Session", Proc.new { |user| raw(Spacer.spacer(user.good_session, user)) }
column "Invited", Proc.new { |user| raw(Spacer.spacer(user.invited, user)) }
column "Friended", Proc.new { |user| raw(Spacer.spacer(user.friended, user)) }
column "Played JT", Proc.new { |user| raw(Spacer.spacer(user.played_jamtrack, user)) }
end
end
end

View File

@ -1,73 +0,0 @@
class Spacer
def self.spacer(val, row)
percentage = ((val * 100) / row.total.to_f).round(1).to_s
('%-5.5s' % percentage).gsub(' ', '&nbsp;') + '%&nbsp;-&nbsp;' + val.to_s
end
end
=begin
select
count(id) as total,
count(first_downloaded_client_at) as downloaded,
count(first_ran_client_at) as ran_client,
count(first_certified_gear_at) as ftue,
count(first_music_session_at) as any_session,
count(first_real_music_session_at) as real_session,
count(first_good_music_session_at) as good_session,
count(first_invited_at) as invited,
count(first_friended_at) as friended,
count(first_subscribed_at) as subscribed
from users where users.created_at >= '2024-11-01' AND users.created_at < '2025-04-01'
select first_name, last_name, email
from users where users.created_at >= '2024-11-01' AND users.created_at < '2025-04-01'
AND first_music_session_at is NULL;
=end
ActiveAdmin.register_page "JamTrack Subscription Cohorts" do
menu :parent => 'Reports'
content :title => "JamTrack Subscription Cohorts" do
h2 "Users Grouped By Month as Paying Subscribers"
table_for User.select(%Q{date_trunc('month', users.created_at) as month,
count(id) as total,
count(first_downloaded_client_at) as downloaded,
count(first_ran_client_at) as ran_client,
count(first_certified_gear_at) as ftue,
count(first_music_session_at) as any_session,
count(first_real_music_session_at) as real_session,
count(first_good_music_session_at) as good_session,
count(first_invited_at) as invited,
count(first_friended_at) as friended,
count(first_subscribed_at) as subscribed,
count(first_played_jamtrack_at) as played_jamtrack
})
.joins(%Q{INNER JOIN LATERAL (
SELECT
j.created_at
FROM
jam_track_rights as j
WHERE
j.user_id = users.id
ORDER BY
j.created_at
LIMIT 1 -- Select only that single row
) j ON (j.created_at - users.created_at) < INTERVAL '2 hours' })
.group("date_trunc('month', users.created_at)").order("date_trunc('month', users.created_at) DESC") do |row|
column "Month", Proc.new { |user| user.month.strftime('%B %Y') }
column "Total", :total
column "Subscribed", Proc.new { |user| raw(Spacer.spacer(user.subscribed, user)) }
column "Downloaded", Proc.new { |user| raw(Spacer.spacer(user.downloaded, user)) }
column "Ran Client", Proc.new { |user| raw(Spacer.spacer(user.ran_client, user)) }
column "FTUE", Proc.new { |user| raw(Spacer.spacer(user.ftue, user)) }
column "Any Session", Proc.new { |user| raw(Spacer.spacer(user.any_session, user)) }
column "2+ Session", Proc.new { |user| raw(Spacer.spacer(user.real_session, user)) }
column "Good Session", Proc.new { |user| raw(Spacer.spacer(user.good_session, user)) }
column "Invited", Proc.new { |user| raw(Spacer.spacer(user.invited, user)) }
column "Friended", Proc.new { |user| raw(Spacer.spacer(user.friended, user)) }
column "Played JT", Proc.new { |user| raw(Spacer.spacer(user.played_jamtrack, user)) }
end
end
end

View File

@ -7,25 +7,22 @@ ActiveAdmin.register_page "SchoolUserUploads" do
puts params puts params
@client = RecurlyClient.new
file = params[:jam_ruby_user][:csv] file = params[:jam_ruby_user][:csv]
created = 0 created = 0
errors = 0 already_existing = 0
updated = 0 array_of_arrays = CSV.read(file.tempfile.path, headers:true, encoding: 'bom|utf-8')
skipped = 0
array_of_arrays = CSV.read(file.tempfile.path, headers: true, encoding: 'bom|utf-8')
array_of_arrays.each do |row| array_of_arrays.each do |row|
school_name = row['School Name'].strip school_name = row['School Name']
school_tag = row['School ID'].strip school_tag = row['School ID']
school = School.autocreate_find_from_upload(school_name, school_tag) school = School.autocreate_find_from_upload(school_name, school_tag)
first_name = row['First Name'].strip first_name = row['First Name']
last_name = row['Last Name'].strip last_name = row['Last Name']
email_address = row['Email Address'].strip.downcase email_address = row['Email Address']
license_start = parse_date(row['License Start Date'].strip) license_start = parse_date(row['License Start Date'])
license_end = parse_date(row['License End Date'].strip) license_end = parse_date(row['License End Date'])
source = row['Source'].strip source = row['Source']
password = SecureRandom.uuid password = SecureRandom.uuid
options = { options = {
first_name: first_name, first_name: first_name,
@ -42,80 +39,30 @@ ActiveAdmin.register_page "SchoolUserUploads" do
password_confirmation: password password_confirmation: password
} }
parse_user_type(row['User Type'].strip, options) parse_user_type(row['User Type'], options)
instrument = Instrument.find('electric guitar') instrument = Instrument.find('electric guitar')
instruments= [{instrument_id: instrument.id, proficiency_level: 3, priority: 1}] instruments= [{instrument_id: instrument.id, proficiency_level: 3, priority: 1}]
options[:instruments] = instruments options[:instruments] = instruments
user = User.signup(options)
existing = User.find_by_email(options[:email]) if user.errors.any?
puts "User #{user.name} #{user.email} had errors"
if existing puts user.errors.inspect
if existing.import_source.nil? already_existing = already_existing + 1
if options[:student]
existing.school = school
existing.is_a_student = true
existing.import_source = options[:import_source]
existing.license_start = options[:license_start]
existing.license_end = options[:license_end]
elsif options[:teacher]
existing.school = school
existing.import_source = options[:import_source]
existing.license_start = options[:license_start]
existing.license_end = options[:license_end]
if existing.teacher.nil?
existing.teacher = Teacher.build_teacher(existing, validate_introduction: true, biography: "Empty biography", school_id: school.id)
end
elsif options[:platform_instructor]
existing.import_source = options[:import_source]
existing.is_platform_instructor = true
existing.license_start = options[:license_start]
existing.license_end = options[:license_end]
end
existing.save
if existing.errors.any?
puts "User #{user.name} #{user.email} had errors"
puts user.errors.inspect
errors = errors + 1
else
@client.sync_subscription(existing)
updated = updated + 1
if options[:student]
UserMailer.school_welcome_message(existing, nil).deliver_now
elsif options[:teacher]
UserMailer.school_welcome_message(existing, nil).deliver_now
elsif options[:platform_instructor]
end
end
else
skipped = skipped + 1
end
else else
user = User.signup(options) puts "User #{user.email} created"
created = created + 1
if user.errors.any?
puts "User #{user.name} #{user.email} had errors"
puts user.errors.inspect
errors = errors + 1
else
@client.sync_subscription(user)
puts "User #{user.email} created"
created = created + 1
end
end end
end end
redirect_to admin_schooluseruploads_path, :notice => "Created #{created}. Updated #{updated}. Errors #{errors}. Skipped #{skipped}" redirect_to admin_schooluseruploads_path, :notice => "Created #{created} school students. Ignored #{already_existing} because already existed."
end end
end end
content do content do
panel "Help" do panel "Help" do
link_to "Download Sample CSV", asset_path("Sample_School_User_Upload.csv", target: "_blank", download: "Sample_School_User_Upload.csv") link_to "Download Sample CSV", asset_path("Sample_School_User_Upload.csv", target: "_blank", download: "Sample_School_User_Upload.csv")
end end
active_admin_form_for User.new, :url => admin_schooluseruploads_upload_schooluseruploads_path, :builder => ActiveAdmin::FormBuilder do |f| active_admin_form_for User.new, :url => admin_schooluseruploads_upload_schooluseruploads_path, :builder => ActiveAdmin::FormBuilder do |f|

View File

@ -1,4 +1,4 @@
ActiveAdmin.register User, :as => 'User_Override' do ActiveAdmin.register User, :as => 'Subscription' do
menu :label => 'Subscription', :parent => 'Users' menu :label => 'Subscription', :parent => 'Users'

View File

@ -1,7 +0,0 @@
ActiveAdmin.register_page "Latency Between Users" do
menu parent: 'Users'
content :title => "Latency Between Users" do
render 'admin/users/users_latency_form'
end
end

View File

@ -1,7 +0,0 @@
ActiveAdmin.register_page "Latency Recommendation" do
menu parent: 'Users'
content :title => "Latency Recommentation" do
render 'admin/users/latency_recommendation_form'
end
end

View File

@ -6,18 +6,15 @@ ActiveAdmin.register JamRuby::User, :as => 'UserSource' do
config.batch_actions = false config.batch_actions = false
config.clear_action_items! config.clear_action_items!
config.filters = false config.filters = false
config.per_page = 250
scope("Paid", default: true) { |scope| scope.unscoped.where(:origin_utm_medium => 'cpc').order('created_at desc') } scope("Most Recent First", default: true) { |scope| scope.unscoped.order('created_at desc')}
scope("Inorganic Source") { |scope| scope.unscoped.where("origin_utm_source != 'organic' OR origin_utm_source IS NULL").order('created_at desc') }
scope("Include Organic") { |scope| scope.unscoped.order('created_at desc') }
index do index do
column "Email" do |user| column "Email" do |user|
user.email user.email
end end
column "Signup (CST)" do |user| column "Bought TestDrive" do |user|
user.created_at.in_time_zone("Central Time (US & Canada)") !user.most_recent_test_drive_purchase.nil? ? "Yes" : "No"
end end
column "UTM Source" do |user| column "UTM Source" do |user|
user.origin_utm_source user.origin_utm_source
@ -28,23 +25,8 @@ ActiveAdmin.register JamRuby::User, :as => 'UserSource' do
column "UTM Campaign" do |user| column "UTM Campaign" do |user|
user.origin_utm_campaign user.origin_utm_campaign
end end
column "UTM ID" do |user|
user.origin_id
end
column "UTM Term" do |user|
user.origin_term
end
column "UTM Content" do |user|
user.origin_content
end
column "Referrer" do |user| column "Referrer" do |user|
user.origin_referrer user.origin_referrer
end end
column "FB Click ID" do |user|
user.facebook_click_id
end
column "FB Browser ID" do |user|
user.facebook_browser_id
end
end end
end end

View File

@ -9,15 +9,11 @@
// require jquery.ui.autocomplete // require jquery.ui.autocomplete
//= require cocoon //= require cocoon
//= require active_admin/base //= require active_admin/base
//= require active_admin/searchable_select
// //= require autocomplete-rails // //= require autocomplete-rails
//= require base //= require base
//= require_tree . //= require_tree .
//= require best_in_place.jquery-ui
$(document).ready(function() { $(document).ready(function() {
jQuery(".best_in_place").best_in_place(); jQuery(".best_in_place").best_in_place()
$.datepicker.setDefaults({
dateFormat: 'yy-mm-dd',
});
}) })

View File

@ -1,3 +0,0 @@
$(document).ready(function() {
jQuery(".ac_bip").bind("ajax:success", function(){ window.location.reload(); });
})

View File

@ -1,110 +0,0 @@
function intToIP(int) {
var part1 = int & 255;
var part2 = ((int >> 8) & 255);
var part3 = ((int >> 16) & 255);
var part4 = ((int >> 24) & 255);
return part4 + "." + part3 + "." + part2 + "." + part1;
}
function handleJamTrackRightsForm() {
var $jamTrackRights = $('form#new_jam_ruby_jam_track_right');
var $jamTrack = $jamTrackRights.find('#jam_ruby_jam_track_right_jam_track_id');
var $jamTrackVal = $jamTrackRights.find('#jam_ruby_jam_track_right_jam_track_id_val')
var $user = $jamTrackRights.find('#jam_ruby_jam_track_right_user_id');
var $userVal = $jamTrackRights.find('#jam_ruby_jam_track_right_user_id_val');
$jamTrack.on('change', function(){
console.log("change jam track");
});
/**
$user.on('change', function(){
console.log("change user");
});
$jamTrack.on('focus', function(){
$userVal.val('')
});*/
$jamTrack.bind('railsAutocomplete.select', function(event, data){
$jamTrackVal.val('');
$jamTrackVal.val(data.item.id);
console.log("jam track selected with id " + data.item.id);
});
$user.bind('railsAutocomplete.select', function(event, data){
$userVal.val('');
$userVal.val(data.item.id);
console.log("user selected with id " + data.item.id);
});
}
function handleUserLatencyForm(){
var $userLatenciesForm = $('form#user_latencies_form');
var $latenciesMyUser = $userLatenciesForm.find('#latencies_my_user');
var $latenciesMyUserId = $userLatenciesForm.find('#latencies_my_user_id');
var $latenciesMyPublicIp = $userLatenciesForm.find('#latencies_my_public_ip');
$latenciesMyUser.on('focus', function(){
$latenciesMyUserId.val('')
});
$latenciesMyUser.bind('railsAutocomplete.select', function(event, data){
$latenciesMyUserId.val('');
$latenciesMyPublicIp.val('');
if(data.item.last_jam_addr){
var ipAddr = intToIP(data.item.last_jam_addr);
$latenciesMyPublicIp.val(ipAddr);
}
$latenciesMyUserId.val(data.item.id);
});
$userLatenciesForm.find('#latencies_user_1').bind('railsAutocomplete.select', function(event, data){
$userLatenciesForm.find('#latencies_user_1_id').val(data.item.id);
});
$userLatenciesForm.find('#latencies_user_2').bind('railsAutocomplete.select', function(event, data){
$userLatenciesForm.find('#latencies_user_2_id').val(data.item.id);
});
$userLatenciesForm.find('#latencies_user_3').bind('railsAutocomplete.select', function(event, data){
$userLatenciesForm.find('#latencies_user_3_id').val(data.item.id);
});
$userLatenciesForm.find('#latencies_user_4').bind('railsAutocomplete.select', function(event, data){
$userLatenciesForm.find('#latencies_user_4_id').val(data.item.id);
});
$userLatenciesForm.find('#latencies_user_5').bind('railsAutocomplete.select', function(event, data){
$userLatenciesForm.find('#latencies_user_5_id').val(data.item.id);
});
}
function handleLatencyRecommendationForm(){
var $latencyRecommendationForm = $('form#latency_recommendation_form');
var $latenciesMyUser = $latencyRecommendationForm.find('#latency_recommendation_my_user');
var $latenciesMyUserId = $latencyRecommendationForm.find('#latency_recommendation_my_user_id');
var $latenciesMyPublicIp = $latencyRecommendationForm.find('#latency_recommendation_my_public_ip');
$latenciesMyUser.on('focus', function(){
$latenciesMyUserId.val('')
});
$latenciesMyUser.bind('railsAutocomplete.select', function(event, data){
$latenciesMyUserId.val('');
$latenciesMyPublicIp.val('');
if(data.item.last_jam_addr){
var ipAddr = intToIP(data.item.last_jam_addr);
$latenciesMyPublicIp.val(ipAddr);
}
$latenciesMyUserId.val(data.item.id);
});
}
$(document).ready(function() {
handleUserLatencyForm();
handleLatencyRecommendationForm();
handleJamTrackRightsForm();
});

View File

@ -15,7 +15,6 @@
// Active Admin's got SASS! // Active Admin's got SASS!
@import "active_admin/mixins"; @import "active_admin/mixins";
@import "active_admin/base"; @import "active_admin/base";
@import "active_admin/searchable_select";
// Overriding any non-variable SASS must be done after the fact. // Overriding any non-variable SASS must be done after the fact.
// For example, to change the default status-tag color: // For example, to change the default status-tag color:

View File

@ -38,7 +38,3 @@
width:auto; width:auto;
} }
} }
.admin_subscription_cohorts #main_content td.col{
font-family:Courier;
}

View File

@ -2,97 +2,49 @@ class ArsesController < ApplicationController
respond_to :json respond_to :json
def index
if params[:code] != Rails.application.config.data_dump_code
render :json => {error: "Unauthorized"}, :status => 401
return
end
@arses = JamRuby::Ars.all
render :json => @arses
end
def update
if params[:code] != Rails.application.config.data_dump_code
render :json => {error: "Unauthorized"}, :status => 401
return
end
begin
# Primary ID lookup
@ars = JamRuby::Ars.find_by_id(params[:id])
# Explicit secondary lookups if primary ID fails
@ars ||= JamRuby::Ars.find_by_id_int(params[:id_int]) if params[:id_int]
@ars ||= JamRuby::Ars.find_by_name(params[:name]) if params[:name]
if @ars.nil?
render :json => {error: "Not Found"}, :status => 404
return
end
allowed = [:password, :username, :active, :beta, :name, :provider, :id_int, :ip, :port, :continent, :country, :city, :subdivision, :latitude, :longitude]
update_hash = {}
allowed.each do |attr|
update_hash[attr] = params[attr] if params.has_key?(attr)
end
if @ars.update_attributes(update_hash, as: :admin)
render :json => @ars, :status => :ok
else
render :json => @ars.errors, :status => :unprocessable_entity
end
rescue => e
render :json => {error: e.message, backtrace: e.backtrace.first(5)}, :status => 500
end
end
# create or update a client_artifact row # create or update a client_artifact row
def get_or_create def get_or_create
begin name = params[:name]
name = params[:name] provider = params[:provider]
provider = params[:provider] active = params[:active]
active = params[:active] ip = params[:ip]
beta = params.has_key?(:beta) ? params[:beta] : true username = params[:username]
ip = params[:ip] password = params[:password]
username = params[:username] topology = params[:topology]
password = params[:password] ars_id = params[:ars_id]
topology = params[:topology] puts "TOPOLOGY #{topology}"
ars_id = params[:ars_id]
# Explicit field-based lookups if ars_id
ars = nil ars = Ars.find_by_id_int(ars_id)
ars = JamRuby::Ars.find_by_id_int(ars_id) if ars_id
ars ||= JamRuby::Ars.find_by_name(name) if name
if ars.nil?
ars = JamRuby::Ars.new
ars.name = name
end
ars.id_int = ars_id if !ars_id.nil?
ars.provider = provider
ars.active = active
ars.beta = params[:beta]
ars.beta = beta
ars.ip = ip
ars.password = password
ars.username = username
if topology
ars.city = topology['city']
ars.country = topology['country']
ars.continent = topology['continent']
ars.latitude = topology['latitude']
ars.longitude = topology['longitude']
ars.subdivision = topology['subdivision']
end
ars.save!
@ars = ars
render :json => {id_int: @ars.id_int, id: @ars.id, name: @ars.name, provider: @ars.provider, active: @ars.active, beta: @ars.beta, ip: @ars.ip}, :status => :ok
rescue => e
render :json => {error: e.message, backtrace: e.backtrace.first(5)}, :status => 500
end end
if ars.nil?
ars = Ars.new
ars.name = name
end
ars.provider = provider
ars.active = active
ars.ip = ip
ars.password = password
ars.username = username
if topology
ars.city = topology['city']
ars.country = topology['country']
ars.continent = topology['continent']
ars.latitude = topology['latitude']
ars.longitude = topology['longitude']
ars.subdivision = topology['subdivision']
end
ars.save
@ars = ars
unless @ars.errors.any?
@ars = Ars.find_by_name(name)
render :json => {id_int: @ars.id_int, id: @ars.id, name: @ars.name, provider: @ars.provider, active: @ars.active, ip: @ars.ip}, :status => :ok
else
response.status = :unprocessable_entity
respond_with @ars
end
end end
end end

View File

@ -1,20 +0,0 @@
module ActiveAdmin
module SubscriptionHelper
def subscription_plan_name(code)
case code
when 'jamrubysilver'
'Silver'
when 'jamrubygold'
'Gold'
when 'jamrubyplatinum'
'Platinum'
when 'jamsubgoldyearly'
'Gold Yearly'
when 'jamsubsilveryearly'
'Silver Yearly'
when 'jamsubplatinumyearly'
'Platinum Yearly'
end
end
end
end

View File

@ -39,4 +39,5 @@ module ApplicationHelper
end end
end end

View File

@ -1,7 +1,7 @@
module MetaHelper module MetaHelper
def version() def version()
"web=#{::JamAdmin::VERSION} lib=#{JamRuby::VERSION}" "web=#{::JamAdmin::VERSION} lib=#{JamRuby::VERSION} db=#{JamDb::VERSION}"
end end
end end

View File

@ -112,19 +112,6 @@ class Cohort < ActiveRecord::Base
def self.cohort_users(cohort) def self.cohort_users(cohort)
User.where(created_at: cohort.group_start..cohort.group_end) User.where(created_at: cohort.group_start..cohort.group_end)
end end
=begin
SELECT played.user_id FROM
(SELECT user_id, COUNT(*) cnt FROM music_sessions_user_history msuh1
WHERE
msuh1.created_at >= '2024-11-01' AND
msuh1.created_at <= '202' AND
EXTRACT(EPOCH FROM (msuh1.session_removed_at - msuh1.created_at)) >= 900 AND
(SELECT COUNT(*) FROM music_sessions_user_history msuh2
WHERE msuh1.music_session_id = msuh2.music_session_id
) > 1
GROUP BY user_id
) played
=end
def _played_online_subquery(constraint) def _played_online_subquery(constraint)
where = if constraint.is_a?(Range) where = if constraint.is_a?(Range)

View File

@ -1,4 +0,0 @@
<%= label_tag :customer_ltv, 'Customer LTV : $' %>
<%= best_in_place GenericState.singleton, :customer_ltv, :as => :input, url: "#{ENV['RAILS_RELATIVE_URL_ROOT']}/admin/generic_states/#{GenericState.singleton.id}", place_holder: "---", :ok_button => 'Save', :cancel_button => 'Cancel', classes: 'ac_bip' %>
<br />
<br />

View File

@ -1,42 +0,0 @@
<h3>Earnings by Month</h3>
<table class="index_table index">
<thead>
<tr>
<th>Month</th>
<th>JamTracks</th>
<th>Subscriptions</th>
<th>Affiliate Earnings</th>
</tr>
</thead>
<tbody>
<% AffiliateMonthlyPayment.index(affiliate_partner.partner_user, {})[0].each do |payment| %>
<tr>
<td>
<%= Date::MONTHNAMES[payment.month] if payment.month %>
<%= payment.year %>
</td>
<td>
<% if payment.jamtracks_sold > 0 %>
JamTracks: <%= pluralize payment.jamtracks_sold, 'unit' %>
<% end %>
</td>
<td>
<%
month_start = Date.new(payment.year, payment.month, 1)
month_end = Date.new(payment.year, payment.month, 1).end_of_month
AffiliateDistribution.subscription_plans_count(affiliate_partner.id, month_start, month_end).each do |plan_count|
%>
<div>
<%= subscription_plan_name(plan_count[:plan]) -%>: <%= pluralize(plan_count.count, 'unit') -%> sold
</div>
<%
end
%>
</td>
<td>
<%= number_to_currency(payment.due_amount_in_cents.to_f/100.0) %>
</td>
</tr>
<% end %>
</tbody>
</table>

View File

@ -2,7 +2,6 @@
<%= f.semantic_errors *f.object.errors.keys %> <%= f.semantic_errors *f.object.errors.keys %>
<%= f.inputs do %> <%= f.inputs do %>
<%= f.input(:partner_name, :input_html => {:maxlength => 128}) %> <%= f.input(:partner_name, :input_html => {:maxlength => 128}) %>
<%= f.input(:partner_user, as: :searchable_select, ajax: true, hint: 'The user that manages/owns this affiliate. They can see affiliate reports') %>
<%= f.input(:entity_type, :as => :select, :collection => AffiliatePartner::ENTITY_TYPES) %> <%= f.input(:entity_type, :as => :select, :collection => AffiliatePartner::ENTITY_TYPES) %>
<%= f.input(:rate) %> <%= f.input(:rate) %>
<% end %> <% end %>

View File

@ -2,6 +2,7 @@
= f.inputs "Details" do = f.inputs "Details" do
= f.input :email, label: 'Email' = f.input :email, label: 'Email'
= f.input :admin = f.input :admin
= f.input :is_onboarder, label: 'Is Support Consultant'
= f.input :subscribe_email, label: 'Subscribed to Emails?' = f.input :subscribe_email, label: 'Subscribed to Emails?'
= f.input :is_platform_instructor, label: 'Is Platform Instructor?' = f.input :is_platform_instructor, label: 'Is Platform Instructor?'
= f.input :gifted_jamtracks, label: 'JamTrack Credits' = f.input :gifted_jamtracks, label: 'JamTrack Credits'
@ -10,8 +11,6 @@
= f.input :city = f.input :city
= f.input :state = f.input :state
= f.input :musician = f.input :musician
= f.input :beta
= f.input :use_video_conferencing_server
= f.inputs "Gear Mods" do = f.inputs "Gear Mods" do
= f.input :show_frame_options, as: :boolean = f.input :show_frame_options, as: :boolean
= f.inputs "Do Not Shows" do = f.inputs "Do Not Shows" do

View File

@ -1,22 +0,0 @@
<%= semantic_form_for 'latency_recommendation', url: user_latency_recommendation_admin_users_path, html: {id: 'latency_recommendation_form'} do |f| %>
<%= f.inputs :name => 'Select user', :class => 'inputs' do %>
<%= f.input :my_user, :as => :autocomplete, url: autocomplete_user_email_admin_users_path, label: 'My user name/email' %>
<%= f.input :my_user_id, as: :hidden %>
<%= f.input :my_public_ip, label: 'My user public IP' %>
<% end %>
<%= f.inputs :name => 'Query parameters', :class => 'inputs' do %>
<%= f.input :query, required: false %>
<%= f.input :instruments_beginner, collection: JamRuby::Instrument.all, input_html: { multiple: true }, required: false %>
<%= f.input :instruments_advanced, collection: JamRuby::Instrument.all, input_html: { multiple: true }, required: false %>
<%= f.input :instruments_expert, collection: JamRuby::Instrument.all, input_html: { multiple: true }, required: false %>
<%= f.input :genres, as: :select, collection: JamRuby::Genre.all, input_html: { multiple: true }, required: false %>
<%= f.input :wifi, as: :select, collection: {'Any': 'any', 'Yes': true, 'No': false }, required: false %>
<%= f.input :max_latency, required: false %>
<%= f.input :offset, input_html: { value: 0 } %>
<%= f.input :limit, input_html: { value: 20 } %>
<% end %>
<%= f.actions do %>
<%= f.action :submit, :as => :button, label: 'Submit' %>
<%= f.action :cancel, :as => :link, label: 'Cancel' %>
<% end %>
<% end %>

View File

@ -1,23 +0,0 @@
<%= semantic_form_for 'latencies', url: user_latencies_admin_users_path, html: {id: 'user_latencies_form'} do |f| %>
<%= f.inputs :name => 'Select user', :class => 'inputs' do %>
<%= f.input :my_user, :as => :autocomplete, url: autocomplete_user_email_admin_users_path, label: 'My user name/email' %>
<%= f.input :my_user_id, as: :hidden %>
<%= f.input :my_public_ip, label: 'My user public IP' %>
<% end %>
<%= f.inputs :name => 'Select other users', :class => 'inputs' do %>
<%= f.input :user_1, :as => :autocomplete, url: autocomplete_user_email_admin_users_path, label: 'Other user 1' %>
<%= f.input :user_1_id, as: :hidden %>
<%= f.input :user_2, :as => :autocomplete, url: autocomplete_user_email_admin_users_path, label: 'Other user 2', required: false %>
<%= f.input :user_2_id, as: :hidden %>
<%= f.input :user_3, :as => :autocomplete, url: autocomplete_user_email_admin_users_path, label: 'Other user 3', required: false %>
<%= f.input :user_3_id, as: :hidden %>
<%= f.input :user_4, :as => :autocomplete, url: autocomplete_user_email_admin_users_path, label: 'Other user 4', required: false %>
<%= f.input :user_4_id, as: :hidden %>
<%= f.input :user_5, :as => :autocomplete, url: autocomplete_user_email_admin_users_path, label: 'Other user 5', required: false %>
<%= f.input :user_5_id, as: :hidden %>
<% end %>
<%= f.actions do %>
<%= f.action :submit, :as => :button, label: 'Submit' %>
<%= f.action :cancel, :as => :link, label: 'Cancel' %>
<% end %>
<% end %>

View File

@ -1,12 +0,0 @@
= semantic_form_for([:admin_users, @user], builder: ActiveAdmin::FormBuilder, :url => @user.new_record? ? add_school_user_admin_users_path : "/admin/users/#{@user.id}/add_school_user") do |f|
= f.inputs "Details" do
= f.input :email, label: 'Email', required: true
= f.input :first_name, required: true
= f.input :last_name, required: true
= f.input :license_start, as: :datepicker, required: true
= f.input :license_end, as: :datepicker, required: true
= f.input :import_source, required: true
= f.input :school_id, as: :select, collection: School.all, required: true
= f.input :user_type, as: :select, collection: ['Student', 'Student Instructor', 'Platform Instructor'], include_blank: false, required: true
= f.actions

View File

@ -1,2 +0,0 @@
<h2><%= @user.name %></h2>
<pre><%= debug @user_latency -%></pre>

View File

@ -1 +0,0 @@
<pre><%= JSON.pretty_generate(JSON.parse(@user_latencies)) -%></pre>

View File

@ -1 +0,0 @@
<pre><%= JSON.pretty_generate(JSON.parse(@latency_recommendation)) -%></pre>

View File

@ -1 +0,0 @@
BUNDLE_GEMFILE=Gemfile.alt RAILS_ENV=development LOCAL_DEV=1 MODERN_OS=1 JAM_RUBY_VERSION=2.4.1 bundle _1.17.3_ exec rails server -b 0.0.0.0 -p 3333

View File

@ -17,7 +17,7 @@ if [ -z "$BUILD_NUMBER" ]; then
GEM_VERSION="0.1.${BUILD_NUMBER}" GEM_VERSION="0.1.${BUILD_NUMBER}"
# copy needed gems to cache so they'll be bundled up in the debian # copy needed gems to cache so they'll be bundled up in the debian
mkdir -p vendor/cache mkdir -p vendor/cache
#cp ../db/target/ruby_package/jam_db-${GEM_VERSION}.gem vendor/cache/ || { echo "unable to copy jam-db gem"; exit 1; } cp ../db/target/ruby_package/jam_db-${GEM_VERSION}.gem vendor/cache/ || { echo "unable to copy jam-db gem"; exit 1; }
cp ../pb/target/ruby/jampb/jampb-${GEM_VERSION}.gem vendor/cache/ || { echo "unable to copy jam-pb gem"; exit 1; } cp ../pb/target/ruby/jampb/jampb-${GEM_VERSION}.gem vendor/cache/ || { echo "unable to copy jam-pb gem"; exit 1; }
cp ../ruby/jam_ruby-${GEM_VERSION}.gem vendor/cache/ || { echo "unable to copy jam-ruby gem"; exit 1; } cp ../ruby/jam_ruby-${GEM_VERSION}.gem vendor/cache/ || { echo "unable to copy jam-ruby gem"; exit 1; }

View File

@ -131,7 +131,7 @@ module JamAdmin
config.email_smtp_starttls_auto = true config.email_smtp_starttls_auto = true
config.verify_email_enabled = false config.verify_email_enabled = false
config.musician_count = '300,000+' config.musician_count = '200,000+'
config.facebook_app_id = ENV['FACEBOOK_APP_ID'] || '468555793186398' config.facebook_app_id = ENV['FACEBOOK_APP_ID'] || '468555793186398'
config.facebook_app_secret = ENV['FACEBOOK_APP_SECRET'] || '546a5b253972f3e2e8b36d9a3dd5a06e' config.facebook_app_secret = ENV['FACEBOOK_APP_SECRET'] || '546a5b253972f3e2e8b36d9a3dd5a06e'
@ -169,8 +169,5 @@ module JamAdmin
config.download_tracker_day_range = 30 config.download_tracker_day_range = 30
config.max_user_ip_address = 10 config.max_user_ip_address = 10
config.max_multiple_users_same_ip = 2 config.max_multiple_users_same_ip = 2
config.latency_data_host = "https://latency-production.naas.jamkazam.com"
config.latency_data_host_auth_code = "amFtQXBpOm5pNWY0eFRjRlpNc0lXNEd4IUR5cQ=="
end end
end end

View File

@ -46,7 +46,4 @@ JamAdmin::Application.configure do
config.email_generic_from = 'nobody-dev@jamkazam.com' config.email_generic_from = 'nobody-dev@jamkazam.com'
config.email_alerts_alias = 'alerts-dev@jamkazam.com' config.email_alerts_alias = 'alerts-dev@jamkazam.com'
config.email_social_alias = 'social-dev@jamkazam.com' config.email_social_alias = 'social-dev@jamkazam.com'
config.latency_data_host = "http://localhost:4001/local"
config.latency_data_host_auth_code = "c2VydmVyOnBhc3N3b3Jk"
end end

View File

@ -1,7 +1,7 @@
class Footer < ActiveAdmin::Component class Footer < ActiveAdmin::Component
def build(namespace) def build(namespace)
super(id: "footer") super(id: "footer")
para "version info: web=#{::JamAdmin::VERSION} lib=#{JamRuby::VERSION}" para "version info: web=#{::JamAdmin::VERSION} lib=#{JamRuby::VERSION} db=#{JamDb::VERSION}"
render :inline => include_gon render :inline => include_gon
end end
end end

View File

@ -1,5 +1,5 @@
Bugsnag.configure do |config| Bugsnag.configure do |config|
config.api_key = "fa0e229f687bcb2c8711fcb80223744e" config.api_key = "7e24985b93dd922a731daca26fc2aa13"
#config.use_ssl = false #config.use_ssl = false
config.notify_release_stages = ["production"] # add 'development' if you want to test a feature locally config.notify_release_stages = ["production"] # add 'development' if you want to test a feature locally
config.auto_notify = true config.auto_notify = true

View File

@ -1,18 +0,0 @@
class JamRuby::JamTrackRight
attr_accessible :jam_track, :user, :jam_track_id_val, :user_id_val, as: :admin
def jam_track_id_val
end
def jam_track_id_val=(val)
end
def user_id_val
end
def user_id_val=(val)
end
end

View File

@ -3,8 +3,4 @@ class JamRuby::JamTrack
# add a custom validation # add a custom validation
def autocomplete_display_name
"#{original_artist} - #{name}"
end
end end

View File

@ -14,15 +14,6 @@ JamAdmin::Application.routes.draw do
namespace :admin do namespace :admin do
resources :users do resources :users do
get :autocomplete_user_email, :on => :collection get :autocomplete_user_email, :on => :collection
get :add_school_user, on: :collection
post :add_school_user, on: :collection
patch :add_school_user, on: :member
post :user_latencies, on: :collection
post :user_latency_recommendation, on: :collection
end
resources :jam_tracks do
get :autocomplete_jam_track_name, :on => :collection
end end
end end
@ -44,8 +35,6 @@ JamAdmin::Application.routes.draw do
match '/api/jam_tracks/released' => 'jam_track#dump_released', :via => :get, as: 'released_jamtracks_csv' match '/api/jam_tracks/released' => 'jam_track#dump_released', :via => :get, as: 'released_jamtracks_csv'
match '/api/arses/register' => 'arses#get_or_create', :via => :post match '/api/arses/register' => 'arses#get_or_create', :via => :post
match '/api/arses' => 'arses#index', :via => :get
match '/api/arses/:id' => 'arses#update', :via => :post
mount Resque::Server.new, :at => "/resque" mount Resque::Server.new, :at => "/resque"

View File

@ -1,45 +1,28 @@
class SpecDb class SpecDb
#TEST_DB_NAME="jam_admin_test" TEST_DB_NAME="jam_admin_test"
def self.reset_test_database def self.recreate_database(db_config)
ENV['RAILS_ENV'] = 'test' recreate_database_jdbc(db_config)
db_config = YAML::load(File.open('config/database.yml'))[ENV['RAILS_ENV']] end
db_test_name = db_config["database"]
def self.recreate_database_jdbc(db_config)
db_test_name = db_config["database"]
# jump into the 'postgres' database, just so we have somewhere to 'land' other than our test db, # jump into the 'postgres' database, just so we have somewhere to 'land' other than our test db,
# since we are going to drop/recreate it # since we are going to drop/recreate it
db_config_admin = db_config.merge({'database' => 'postgres', 'schema_search_path' => 'public'}) db_config["database"] = "postgres"
ActiveRecord::Base.establish_connection(db_config_admin) ActiveRecord::Base.establish_connection(db_config)
ActiveRecord::Base.connection.execute("DROP DATABASE IF EXISTS #{db_test_name}") ActiveRecord::Base.connection.execute("DROP DATABASE IF EXISTS #{db_test_name}")
ActiveRecord::Base.connection.execute("CREATE DATABASE #{db_test_name}") ActiveRecord::Base.connection.execute("CREATE DATABASE #{db_test_name}")
db_config["database"] = db_test_name
JamDb::Migrator.new.migrate(:dbname => db_config["database"], :user => db_config["username"], :password => db_config["password"], :host => db_config["host"])
end end
def self.recreate_database def self.recreate_database_pg
self.reset_test_database
JamRuby::TestSupport.migrate_database conn = PG::Connection.open("dbname=postgres")
conn.exec("DROP DATABASE IF EXISTS #{TEST_DB_NAME}")
conn.exec("CREATE DATABASE #{TEST_DB_NAME}")
JamDb::Migrator.new.migrate(:dbname => TEST_DB_NAME)
end end
# def self.recreate_database(db_config)
# recreate_database_jdbc(db_config)
# end
# def self.recreate_database_jdbc(db_config)
# db_test_name = db_config["database"]
# # jump into the 'postgres' database, just so we have somewhere to 'land' other than our test db,
# # since we are going to drop/recreate it
# db_config["database"] = "postgres"
# ActiveRecord::Base.establish_connection(db_config)
# ActiveRecord::Base.connection.execute("DROP DATABASE IF EXISTS #{db_test_name}")
# ActiveRecord::Base.connection.execute("CREATE DATABASE #{db_test_name}")
# db_config["database"] = db_test_name
# JamDb::Migrator.new.migrate(:dbname => db_config["database"], :user => db_config["username"], :password => db_config["password"], :host => db_config["host"])
# end
# def self.recreate_database_pg
# conn = PG::Connection.open("dbname=postgres")
# conn.exec("DROP DATABASE IF EXISTS #{TEST_DB_NAME}")
# conn.exec("CREATE DATABASE #{TEST_DB_NAME}")
# JamDb::Migrator.new.migrate(:dbname => TEST_DB_NAME)
# end
end end

View File

@ -1,25 +1,19 @@
ENV["RAILS_ENV"] ||= 'test' ENV["RAILS_ENV"] ||= 'test'
require 'simplecov' require 'simplecov'
# provision database # provision database
require 'active_record' require 'active_record'
# require 'jam_db' require 'jam_db'
require 'spec_db' require 'spec_db'
require 'yaml'
# recreate test database and migrate it # recreate test database and migrate it
db_config = YAML::load(File.open('config/database.yml'))["test"] db_config = YAML::load(File.open('config/database.yml'))["test"]
#SpecDb::recreate_database(db_config) SpecDb::recreate_database(db_config)
ActiveRecord::Base.establish_connection(db_config) ActiveRecord::Base.establish_connection(YAML::load(File.open('config/database.yml'))["test"])
# This file is copied to spec/ when you run 'rails generate rspec:install' # This file is copied to spec/ when you run 'rails generate rspec:install'
require 'jam_ruby' require 'jam_ruby'
SpecDb::recreate_database
require File.expand_path("../../config/environment", __FILE__) require File.expand_path("../../config/environment", __FILE__)

View File

@ -1 +0,0 @@
# trigger build

View File

@ -1,98 +0,0 @@
image: node:14.21.3
pipelines:
branches:
develop:
- step:
name: Build Staging
script:
- pushd jam-ui
- npm install
- popd
- pushd jam-ui/cicd
- npm install
- NODE_ENV=production PUBLIC_URL=https://staging.jamkazam.com REACT_APP_ORIGIN=staging.jamkazam.com REACT_APP_BASE_URL=https://staging.jamkazam.com REACT_APP_CLIENT_BASE_URL=https://staging.jamkazam.com REACT_APP_API_BASE_URL=https://staging.jamkazam.com/api REACT_APP_BITBUCKET_BUILD_NUMBER=$BITBUCKET_BUILD_NUMBER REACT_APP_BITBUCKET_COMMIT=$BITBUCKET_COMMIT REACT_APP_GOOGLE_ANALYTICS_ID=G-8W0GTL53NT ENVIRONMENT=staging ./generate.sh
- popd
- cd jam-ui
- NODE_ENV=production CI=false PUBLIC_URL=https://staging.jamkazam.com REACT_APP_ORIGIN=staging.jamkazam.com REACT_APP_CLIENT_BASE_URL=https://staging.jamkazam.com REACT_APP_BASE_URL=https://staging.jamkazam.com REACT_APP_API_BASE_URL=https://staging.jamkazam.com/api REACT_APP_BITBUCKET_BUILD_NUMBER=$BITBUCKET_BUILD_NUMBER REACT_APP_BITBUCKET_COMMIT=$BITBUCKET_COMMIT REACT_APP_GOOGLE_ANALYTICS_ID=G-8W0GTL53NT npm run build
artifacts:
- jam-ui/build/**
- step:
name: Deploy to staging - SPA
script:
- pipe: atlassian/aws-s3-deploy:1.6.2
variables:
S3_BUCKET: "jamkazam-ui/stg"
LOCAL_PATH: "jam-ui/build"
EXTRA_ARGS: "--exclude=*backing-tracks/*"
- step:
name: Deploy to staging - backing-tracks
script:
- pipe: atlassian/aws-s3-deploy:1.6.2
variables:
S3_BUCKET: "jamkazam-ui/stg/backing-tracks"
LOCAL_PATH: "jam-ui/build/backing-tracks"
EXTRA_ARGS: "--exclude=*.js --content-type text/html"
- step:
name: Deploy to staging - backing-tracks js
script:
- pipe: atlassian/aws-s3-deploy:1.6.2
variables:
S3_BUCKET: "jamkazam-ui/stg/js"
LOCAL_PATH: "jam-ui/build/js"
EXTRA_ARGS: "--content-type text/javascript"
# - step:
# name: Deploy to staging - invalidate cloudfront distribution
# deployment: staging
# script:
# - pipe: atlassian/aws-cloudfront-invalidate:0.10.1
# variables:
# DISTRIBUTION_ID: "E2AQIC9RSON94Q" # ESQDIABYLT0RV
custom:
build-and-deploy-to-production:
- step:
name: Build Production
script:
- pushd jam-ui
- npm install
- popd
- pushd jam-ui/cicd
- npm install
- NODE_ENV=production ENVIRONMENT=production PUBLIC_URL=https://www.jamkazam.com REACT_APP_ORIGIN=jamkazam.com REACT_APP_BASE_URL=https://www.jamkazam.com REACT_APP_CLIENT_BASE_URL=https://www.jamkazam.com REACT_APP_API_BASE_URL=https://www.jamkazam.com/api REACT_APP_BITBUCKET_BUILD_NUMBER=$BITBUCKET_BUILD_NUMBER REACT_APP_BITBUCKET_COMMIT=$BITBUCKET_COMMIT REACT_APP_GOOGLE_ANALYTICS_ID=G-SPTNJRW7WB ./generate.sh
- popd
- cd jam-ui
- NODE_ENV=production CI=false PUBLIC_URL=https://www.jamkazam.com REACT_APP_ORIGIN=jamkazam.com REACT_APP_BASE_URL=https://www.jamkazam.com REACT_APP_CLIENT_BASE_URL=https://www.jamkazam.com REACT_APP_API_BASE_URL=https://www.jamkazam.com/api REACT_APP_BITBUCKET_BUILD_NUMBER=$BITBUCKET_BUILD_NUMBER REACT_APP_BITBUCKET_COMMIT=$BITBUCKET_COMMIT REACT_APP_GOOGLE_ANALYTICS_ID=G-SPTNJRW7WB npm run build
artifacts:
- jam-ui/build/**
- step:
name: Deploy to production - SPA
script:
- pipe: atlassian/aws-s3-deploy:1.6.2
variables:
S3_BUCKET: "jamkazam-ui/prd"
LOCAL_PATH: "jam-ui/build"
EXTRA_ARGS: "--exclude=*backing-tracks/*"
- step:
name: Deploy to production - backing-tracks
script:
- pipe: atlassian/aws-s3-deploy:1.6.2
variables:
S3_BUCKET: "jamkazam-ui/prd/backing-tracks"
LOCAL_PATH: "jam-ui/build/backing-tracks"
EXTRA_ARGS: "--exclude=*.js --content-type text/html"
- step:
name: Deploy to production - backing-tracks js
script:
- pipe: atlassian/aws-s3-deploy:1.6.2
variables:
S3_BUCKET: "jamkazam-ui/prd/js"
LOCAL_PATH: "jam-ui/build/js"
EXTRA_ARGS: "--content-type text/javascript"
#- step:
# name: Deploy to production - invalidate cloudfront distribution
# deployment: production
# script:
# - pipe: atlassian/aws-cloudfront-invalidate:0.10.1
# variables:
# DISTRIBUTION_ID: "ESQDIABYLT0RV"

25
build
View File

@ -1,6 +1,5 @@
#!/bin/bash #!/bin/bash
# RUN_SLOW_TESTS, RUN_AWS_TESTS, SKIP_KARMA=1 SHOW_JS_ERRORS=1 PACKAGE=1 # RUN_SLOW_TESTS, RUN_AWS_TESTS, SKIP_KARMA=1 SHOW_JS_ERRORS=1 PACKAGE=1
# WORKSPACE=/var/lib/jenkins/jobs/jam-web/workspace # WORKSPACE=/var/lib/jenkins/jobs/jam-web/workspace
@ -10,6 +9,12 @@ export BUNDLE_JOBS=1 # 6, which i want to use, makes the whole server crawl
echo "" echo ""
echo "BUILDING JAM-DB"
pushd db > /dev/null
./jenkins
popd > /dev/null
echo ""
echo "BUILDING JAM-PB" echo "BUILDING JAM-PB"
pushd pb > /dev/null pushd pb > /dev/null
@ -64,6 +69,24 @@ if [ ! -z "$PACKAGE" ]; then
# if still going, then push all debs up # if still going, then push all debs up
if [[ "$GIT_BRANCH" == *develop* || "$GIT_BRANCH" == *master* || "$GIT_BRANCH" == *release* || "$GIT_BRANCH" == *feature* || "$GIT_BRANCH" == *hotfix* ]]; then if [[ "$GIT_BRANCH" == *develop* || "$GIT_BRANCH" == *master* || "$GIT_BRANCH" == *release* || "$GIT_BRANCH" == *feature* || "$GIT_BRANCH" == *hotfix* ]]; then
echo ""
echo "PUSHING DB ARTIFACTS"
pushd db > /dev/null
echo "publishing ubuntu packages (.deb)"
for f in `find target -name '*.deb'`; do
DEBNAME=`basename $f`
DEBPATH="$f"
echo "publishing $DEBPATH to deb server"
curl -f -T $DEBPATH $DEB_SERVER/$DEBNAME
if [ "$?" != "0" ]; then
echo "deb publish failed of $DEBPATH"
exit 1
fi
done
echo "done publishing debs"
popd > /dev/null
echo "" echo ""
echo "PUSHING WEB" echo "PUSHING WEB"
pushd web > /dev/null pushd web > /dev/null

1
db/.ruby-version Normal file
View File

@ -0,0 +1 @@
2.0.0-p247

View File

@ -1,10 +1,5 @@
source 'http://rubygems.org' source 'http://rubygems.org'
ruby_version = ENV["JAM_RUBY_VERSION"]
ruby_version = "2.3.1" if ruby_version.nil?
ruby ruby_version
# Assumes you have already cloned pg_migrate_ruby in your workspace # Assumes you have already cloned pg_migrate_ruby in your workspace
# $ cd [workspace] # $ cd [workspace]
# $ git clone https://github.com/sethcall/pg_migrate_ruby # $ git clone https://github.com/sethcall/pg_migrate_ruby

View File

@ -17,8 +17,5 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
pg_migrate (= 0.1.14)! pg_migrate (= 0.1.14)!
RUBY VERSION
ruby 2.4.1p111
BUNDLED WITH BUNDLED WITH
2.2.7 1.11.2

View File

@ -152,12 +152,3 @@ CREATE INDEX recorded_tracks_recording_id_idx ON recorded_tracks USING btree (re
CREATE INDEX recorded_backing_tracks_user_id_idx ON recorded_backing_tracks USING btree (user_id); CREATE INDEX recorded_backing_tracks_user_id_idx ON recorded_backing_tracks USING btree (user_id);
CREATE INDEX recorded_backing_tracks_recording_id_idx ON recorded_backing_tracks USING btree (recording_id); CREATE INDEX recorded_backing_tracks_recording_id_idx ON recorded_backing_tracks USING btree (recording_id);
CREATE INDEX mixes_recording_id_idx ON mixes USING btree (recording_id); CREATE INDEX mixes_recording_id_idx ON mixes USING btree (recording_id);
CREATE INDEX msuh_id_idx ON music_sessions_user_history USING btree (id);
CREATE INDEX quick_mixes_user_id_idx ON quick_mixes USING btree (user_id);
CREATE INDEX recorded_videos_user_id_idx ON recorded_videos USING btree (user_id);
CREATE INDEX music_sessions_user_id_idx ON music_sessions USING btree (user_id);
ALTER TABLE users ADD COLUMN used_current_month INT;
ALTER TABLE users ADD COLUMN used_month_play_time INT;
ALTER TABLE bands ADD COLUMN school_id INT;

View File

View File

@ -1,6 +0,0 @@
# Browsers that we support
last 1 version
> 0.2%
not op_mini all
not dead

View File

@ -1,16 +0,0 @@
HOST=beta.jamkazam.local
PORT=4000
REACT_APP_ORIGIN=jamkazam.local
REACT_APP_BASE_URL=http://beta.jamkazam.local:4000
REACT_APP_CLIENT_BASE_URL=http://www.jamkazam.local:3000
REACT_APP_API_BASE_URL=http://www.jamkazam.local:3000/api
REACT_APP_BITBUCKET_BUILD_NUMBER=dev
REACT_APP_BITBUCKET_COMMIT=dev
REACT_APP_ENV=development
REACT_APP_RECAPTCHA_ENABLED=false
REACT_APP_SITE_KEY=6Let8dgSAAAAAFheKGWrs6iaq_hIlPOZ2f3Bb56B
REACT_APP_GOOGLE_ANALYTICS_ID=G-MC9BTWXWY4
PUBLIC_URL=
REACT_APP_COOKIE_DOMAIN=.jamkazam.local
REACT_APP_RECURLY_PUBLIC_API_KEY=ewr1-hvDV1xQxDw0HPaaRFP4KNE
REACT_APP_BRAINTREE_TOKEN=sandbox_pgjp8dvs_5v5rwm94m2vrfbms

View File

@ -1,13 +0,0 @@
HOST=beta.jamkazam.local
PORT=4000
REACT_APP_ORIGIN=jamkazam.local
REACT_APP_BASE_URL=http://beta.jamkazam.local:4000
REACT_APP_CLIENT_BASE_URL=http://www.jamkazam.local:3000
REACT_APP_API_BASE_URL=http://www.jamkazam.local:3000/api
REACT_APP_BITBUCKET_BUILD_NUMBER=dev
REACT_APP_BITBUCKET_COMMIT=dev
REACT_APP_ENV=development
REACT_APP_COOKIE_DOMAIN=.jamkazam.com
REACT_APP_GOOGLE_ANALYTICS_ID=G-MC9BTWXWY4
REACT_APP_RECURLY_PUBLIC_API_KEY=
REACT_APP_BRAINTREE_TOKEN=

View File

@ -1,13 +0,0 @@
HOST=beta.jamkazam.com
PORT=4000
REACT_APP_ORIGIN=jamkazam.com
REACT_APP_BASE_URL=https://www.jamkazam.com
REACT_APP_CLIENT_BASE_URL=https://www.jamkazam.com
REACT_APP_API_BASE_URL=https://www.jamkazam.com/api
REACT_APP_ENV=production
REACT_APP_RECAPTCHA_ENABLED=true
REACT_APP_SITE_KEY=6Let8dgSAAAAAFheKGWrs6iaq_hIlPOZ2f3Bb56B
REACT_APP_COOKIE_DOMAIN=.jamkazam.com
REACT_APP_GOOGLE_ANALYTICS_ID=G-SPTNJRW7WB
REACT_APP_RECURLY_PUBLIC_API_KEY=ewr1-hvDV1xQxDw0HPaaRFP4KNE
REACT_APP_BRAINTREE_TOKEN=production_hc7z69yq_pwwc6zm3d478kfrh

View File

@ -1,13 +0,0 @@
HOST=beta.staging.jamkazam.com
PORT=4000
REACT_APP_ORIGIN=staging.jamkazam.com
REACT_APP_BASE_URL=https://staging.jamkazam.com
REACT_APP_CLIENT_BASE_URL=https://staging.jamkazam.com
REACT_APP_API_BASE_URL=https://staging.jamkazam.com/api
REACT_APP_ENV=staging
REACT_APP_RECAPTCHA_ENABLED=false
REACT_APP_SITE_KEY=6Let8dgSAAAAAFheKGWrs6iaq_hIlPOZ2f3Bb56B
REACT_APP_COOKIE_DOMAIN=.staging.jamkazam.com
REACT_APP_GOOGLE_ANALYTICS_ID=G-8W0GTL53NT
REACT_APP_RECURLY_PUBLIC_API_KEY=ewr1-AjUHUfcLtIsPdtetD4mj2x
REACT_APP_BRAINTREE_TOKEN=sandbox_pgjp8dvs_5v5rwm94m2vrfbms

View File

@ -1,8 +0,0 @@
{
"extends": ["react-app", "prettier", "plugin:react/recommended"],
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error",
"react/no-unescaped-entities": 0
}
}

37
jam-ui/.gitignore vendored
View File

@ -1,37 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
.cypress.env.json
npm-debug.log*
yarn-debug.log*
yarn-error.log*
/.idea
/.vscode
/test-results
/cypress/videos/
/cypress/screenshots/
/public/backing-tracks
/public/js

View File

@ -1,31 +0,0 @@
# Using the node alpine image to build the React app
image: node:alpine
# Announce the URL as per CRA docs
# https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#advanced-configuration
variables:
PUBLIC_URL: /react-falcon
# Cache node modules - speeds up future builds
cache:
paths:
- node_modules
# Name the stages involved in the pipeline
stages:
- deploy
# Job name for gitlab to recognise this results in assets for Gitlab Pages
# https://docs.gitlab.com/ee/user/project/pages/introduction.html#gitlab-pages-requirements
pages:
stage: deploy
script:
- npm install # Install all dependencies
- npm run build --prod # Build for prod
- mv public _public # CRA and gitlab pages both use the public folder. Only do this in a build pipeline.
- mv build public # Move build files to public dir for Gitlab Pages
- cp public/index.html public/404.html # Required for react router browser history, but helps with https://blog.pshrmn.com/how-single-page-applications-work/
artifacts:
paths:
- public # The built files for Gitlab Pages to serve
only:
- master # Only run on master branch

View File

@ -1 +0,0 @@
v14.21.3

View File

@ -1,4 +0,0 @@
{
"singleQuote": true,
"printWidth": 120
}

View File

@ -1 +0,0 @@
2.7.18

View File

@ -1,56 +0,0 @@
# JamKazam new react frontend UI/UX
`jam-ui` is a react app created using `create-react-app` utility. to run the app on your development environment you need to `cd jam-ui` and run `npm run start`
The changes to the source files are auto-loaded but sometimes you might need to force close it by crtl+c and then start manually.
The application files goes under `src` and the react components are placed under `src/components` directory. We have a convention of naming the files using JK prefix in the filename. For example `JKMusicSessions`.
The routes are defined in `jam-ui/src/components/dashboard/JKDashboardMain.js`
## Running react app
In production this React app is supposed to run on beta.jamkazam.com subdomain which is same origin domain to the production Rails app (www.jamkazam.com). This way we utilize same session based user authentication of Rails web app for authenticating users. (It looks for remember_token session cookie in headers and if it is not availale redirect the user to Rails web app sign in page)
The DOMAIN and PORT running this app is defined in env.production file. This file also has env variables for connecting with Rails app. (When setting up in development you can copy the content of env.development.example in to env.development.local and change them according to your host setup)
HOST=beta.jamkazam.local
PORT=4000
REACT_APP_CLIENT_BASE_URL=http://www.jamkazam.local:3000
REACT_APP_API_BASE_URL=http://www.jamkazam.local:3000/api
## Subdomains setup (development)
You need 2 host records created for React and and Rails app. For example
127.0.0.1 www.jamkazam.local #for Rails app
127.0.0.1 beta.jamkazam.local #for React app
## Installing npm dependencies
cd jam-ui
npm install
## Running the app
cd jam-ui
npm run start
This will open it in a borwser window at http://beta.jamkazam.local:3000. Of course for it to work you also need Rails (web) app and websocket app (websocket-gateway) running.
## Working with JamTracks
if you have the latest from develop, you can go:
```
cd cicd
npm install
./export_personal_jamtracks.sh
./generate.js
open http://beta.jamkazam.local:4000/backing-tracks/ac-dc/back-in-black.html
```
You can also do none of the above, and go straight to:
http://beta.jamkazam.local:4000/public/backing-tracks/ac-dc/back-in-black
I tried to make it so the SPA has 'secret routes' to these pages, which is convenient for us dev & testing
but also tried to make it convenient to run the cicd approach of actually generating separate pages for each landing page (which is what those 5 steps cover)

View File

@ -1,6 +0,0 @@
build
output
node_modules
public
jam_track_tracks_for_jam_ui*

View File

@ -1 +0,0 @@
22

View File

@ -1,7 +0,0 @@
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"ignore": [
"../src/components/e-commerce/*.js"
]
}

View File

@ -1,29 +0,0 @@
import 'react-app-polyfill/ie9';
import 'react-app-polyfill/stable';
import React from "react";
import ReactDOM from "react-dom";
import Main from "../src/Main.js"
import TemplatePage from "../src/components/jamtracks/JKJamTracksLandingTemplatePage.js"
import ArtistTemplatePage from "../src/components/jamtracks/JKJamTracksArtistLandingTemplatePage.js"
import '../src/helpers/initFA';
import '../src/i18n/config';
const rootElement = document.getElementById("root");
// Ensure props are passed correctly (or fetch from the server)
const props = window.jamtrack_data;
console.log('init', props, rootElement);
// Hydrate the server-rendered React component
//ReactDOM.hydrate(React.createElement(TemplatePage, props), rootElement);
ReactDOM.render(
<Main>
{props.song ? <TemplatePage {...props} /> : <ArtistTemplatePage {...props} /> }
</Main>, rootElement
);

View File

@ -1,25 +0,0 @@
#!/bin/bash
# check if 1st argument spceified; if it is, then set that to SAVE_TO
if [ -n "$1" ]; then
SAVE_TO="$1"
else
SAVE_TO=/tmp
fi
echo "Saving to $SAVE_TO"
psql jam -c "COPY( select id, original_artist, name , original_artist_slug, name_slug, plan_code, slug, allow_free, ('https://www.jamkazam.com/backing-tracks/' || original_artist_slug || '/' || name_slug) as \"URL\", (select name from jam_track_licensors l where l.id = licensor_id) as \"Licensor\", vendor_id as \"Vendor ID\" FROM jam_tracks) TO '$SAVE_TO/jam_tracks_for_jam_ui.$USER.csv' with CSV HEADER;"
//https://jamkazam-public.s3.amazonaws.com
# dump all artists
psql jam -c "COPY( select original_artist, original_artist_slug, ('https://www.jamkazam.com/backing-tracks/' || original_artist_slug ) as \"URL\" FROM jam_tracks group by original_artist, original_artist_slug) TO '$SAVE_TO/jam_tracks_for_jam_ui_artists.$USER.csv' with CSV HEADER;"
psql jam -c "COPY( select id, part, instrument_id, (select description from instruments where id = instrument_id) as instrument_description, track_type, position, preview_mp3_url, preview_url as preview_ogg_url, preview_aac_url from jam_track_tracks) TO '$SAVE_TO/jam_track_tracks_for_jam_ui.$USER.csv' with CSV HEADER;"
echo "Moving personal files to jamtracks-for-env"
mkdir -p jamtracks-for-env
sudo mv $SAVE_TO/jam_tracks_for_jam_ui.$USER.csv jamtracks-for-env
sudo mv $SAVE_TO/jam_tracks_for_jam_ui_artists.$USER.csv jamtracks-for-env
sudo mv $SAVE_TO/jam_track_tracks_for_jam_ui.$USER.csv jamtracks-for-env

View File

@ -1,39 +0,0 @@
#!/bin/bash
# Ensure the correct number of arguments
if [ "$#" -lt 2 ]; then
echo "Usage: $0 <save_to_path> <server_env>"
exit 1
fi
SAVE_TO="$1"
server_env="$2"
# Validate server_env
if [ "$server_env" != "staging" ] && [ "$server_env" != "production" ]; then
echo "Error: server_env must be either 'staging' or 'production'"
exit 1
fi
# Determine SSH target
if [ "$server_env" == "staging" ]; then
SSH_TARGET="jam@int.jamkazam.com"
else
SSH_TARGET="jam@db.jamkazam.com"
fi
echo "Saving to $SAVE_TO on $server_env"
# Run psql commands remotely
ssh $SSH_TARGET "psql jam -c \"COPY( select id, original_artist, name, original_artist_slug, name_slug, plan_code, slug, allow_free, ('https://www.jamkazam.com/backing-tracks/' || original_artist_slug || '/' || name_slug) as \"URL\", (select name from jam_track_licensors l where l.id = licensor_id) as \"Licensor\" FROM jam_tracks order by id::int) TO '$SAVE_TO/jam_tracks_for_jam_ui.$server_env.csv' with CSV HEADER;\""
ssh $SSH_TARGET "psql jam -c \"COPY( select original_artist, original_artist_slug, ('https://www.jamkazam.com/backing-tracks/' || original_artist_slug ) as \"URL\" FROM jam_tracks group by original_artist, original_artist_slug order by original_artist) TO '$SAVE_TO/jam_tracks_for_jam_ui_artists.$server_env.csv' with CSV HEADER;\""
ssh $SSH_TARGET "psql jam -c \"COPY( select id, part, instrument_id, (select description from instruments where id = instrument_id) as instrument_description, track_type, position, preview_mp3_url, preview_url as preview_ogg_url, preview_aac_url from jam_track_tracks order by jam_track_id::int) TO '$SAVE_TO/jam_track_tracks_for_jam_ui.$server_env.csv' with CSV HEADER;\""
# Move files locally from the remote server
scp $SSH_TARGET:"$SAVE_TO/jam_tracks_for_jam_ui.$server_env.csv" jamtracks-for-env
scp $SSH_TARGET:"$SAVE_TO/jam_tracks_for_jam_ui_artists.$server_env.csv" jamtracks-for-env
scp $SSH_TARGET:"$SAVE_TO/jam_track_tracks_for_jam_ui.$server_env.csv" jamtracks-for-env
echo "Files moved successfully to local machine"

View File

@ -1,337 +0,0 @@
const fs = require("fs");
const path = require("path");
const csv = require("csv-parser");
const React = require("react");
const dotenv = require("dotenv");
const ReactDOMServer = require("react-dom/server");
const TemplatePageModule = require("./build/components/jamtracks/JKJamTracksLandingTemplatePage");
const ArtistTemplatePageModule = require("./build/components/jamtracks/JKJamTracksArtistLandingTemplatePage");
var csvFilePath = `jamtracks-for-env/jam_tracks_for_jam_ui.${process.env.USER}.csv`
var artistCsvFilePath = `jamtracks-for-env/jam_tracks_for_jam_ui_artists.${process.env.USER}.csv`
var sitemapPath = path.join(__dirname, "..", "public", "sitemap.xml");
const clear_sitemap = () => {
fs.writeFileSync(sitemapPath, "");
// Add the root element
fs.writeFileSync(sitemapPath, `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n`, { flag: 'a' });
// Add the root url
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}</loc></url>\n`, { flag: 'a' });
// Add standard URLs specific to this site, such as:
// All prefix with /public
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/</loc></url>\n`, { flag: 'a' });
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/public/privacy</loc></url>\n`, { flag: 'a' } );
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/public/help</loc></url>\n`, { flag: 'a' } );
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/public/knowledge-base</loc></url>\n`, { flag: 'a' } );
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/public/help-desk</loc></url>\n`, { flag: 'a' } );
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/public/forum</loc></url>\n`, { flag: 'a' } );
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/public/unsubscribe</loc></url>\n`, { flag: 'a' } );
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/public/downloads</loc></url>\n`, { flag: 'a' } );
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/public/downloads-legacy</loc></url>\n`, { flag: 'a' } );
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/auth/login</loc></url>\n`, { flag: 'a' });
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/auth/signup</loc></url>\n`, { flag: 'a' } );
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/auth/forget-password</loc></url>\n`, { flag: 'a' } );
// Add the closing root element
}
const add_song_to_sitemap = (artistSlug, songSlug) => {
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/backing-tracks/${artistSlug}/${songSlug}</loc></url>\n`, { flag: 'a' });
}
const add_artist_to_sitemap = (artistSlug) => {
fs.writeFileSync(sitemapPath, `<url><loc>${process.env.REACT_APP_BASE_URL}/backing-tracks/${artistSlug}</loc></url>\n`, { flag: 'a' });
}
const close_sitemap = () => {
fs.writeFileSync(sitemapPath, "</urlset>", { flag: 'a' } );
}
/**
* Loads a CSV file into an array of objects.
* @param {string} csvPath - The path to the CSV file.
* @returns {Promise<Array<Object>>} - A promise that resolves with the parsed CSV data.
*/
const load_csv = (csvPath) => {
return new Promise((resolve, reject) => {
const results = [];
fs.createReadStream(csvPath)
.pipe(csv())
.on('data', (data) => results.push(data))
.on('end', () => resolve(results))
.on('error', (error) => reject(error));
});
};
/**
* Finds all songs for a given artist based on the original_artist_slug
* and sorts them alphabetically by the `slug` field.
* @param {string} artistSlug - The original_artist_slug to match.
* @param {Array<Object>} songsCsv - The songs CSV data.
* @returns {Array<Object>} - A sorted array of matching song objects.
*/
const collect_songs_for_artist = (artistSlug, songsCsv) => {
return songsCsv
.filter((song) => song.original_artist_slug === artistSlug)
.sort((a, b) => a.slug.localeCompare(b.slug)); // Sort alphabetically by slug
};
const init = () => {
const node_env = process.env.NODE_ENV || 'development';
const environment = process.env.ENVIRONMENT || 'development';
console.log(`environment=${environment} node_env=${node_env}`);
console.log(dotenv.config({ path: `../.env.${environment}` }));
if (environment === "production" || environment === "staging") {
csvFilePath = `jamtracks-for-env/jam_tracks_for_jam_ui.${environment}.csv`;
artistCsvFilePath = `jamtracks-for-env/jam_tracks_for_jam_ui_artists.${environment}.csv`;
}
console.log("Song csv file", csvFilePath);
console.log("Artist csv file", artistCsvFilePath);
if (!process.env.PUBLIC_URL) {
console.log("setting public url", process.env.REACT_APP_BASE_URL);
process.env.PUBLIC_URL = process.env.REACT_APP_BASE_URL;
}
clear_sitemap();
//const __dirname = path.resolve(path.dirname(''));
console.log("init done successfully")
}
const generateSongPages = async (render) => {
const rows = [];
const OUTPUT_DIR = path.join(__dirname, "..", "public", "backing-tracks");
if (!fs.existsSync(OUTPUT_DIR)) {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}
console.log("generatPages starting")
const TemplatePage = TemplatePageModule.default;
fs.createReadStream(csvFilePath)
.pipe(csv())
.on("data", (row) => rows.push(row))
.on("end", async () => {
console.log(`Processing ${rows.length} rows...`);
for (const row of rows) {
// id, original_artist, name, original_artist_slug, name_slug, plan_code, slug, URL, licensor, vendor_id
const { id, original_artist, name, original_artist_slug, name_slug, plan_code, slug, allow_free } = row;
const artist = original_artist;
const song = name;
const location = `/backing-tracks/${original_artist_slug}/${name_slug}`;
const fullPath = process.env.REACT_APP_BASE_URL + location;
const logoPath = process.env.REACT_APP_BASE_URL + "/favicon.svg";
add_song_to_sitemap(original_artist_slug, name_slug);
console.log(`Generating ${artist} - ${song}`);
const html = render
? ReactDOMServer.renderToStaticMarkup(
React.createElement(TemplatePage, { id, plan_code, slug, artist, song, location })
)
: "";
const fullHtml = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="shortcut icon" href="/favicon.svg">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${artist} - ${song} - Free Backing Track</title>
<link rel="stylesheet" href="${process.env.REACT_APP_BASE_URL}/css/theme.css">
<meta name="description" content="Get free ${song} by ${artist} backing track, plus free tools to mute any part, slow down for practice, record yourself, more">
<meta name="keywords" content="Backing Track, ${artist}, ${song}, Instrumental">
<meta name="author" content="JamKazam">
<!-- Open Graph (Facebook, LinkedIn, etc.) -->
<meta property="og:title" content="${artist} - ${song} | Free Backing Track">
<meta property="og:description" content="Get free ${song} by ${artist} backing track, plus free tools to mute any part, slow down for practice, record yourself, more">
<meta property="og:image" content="${logoPath}">
<meta property="og:url" content="${fullPath}">
<meta property="og:type" content="music.song">
<!-- Twitter Cards -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="${artist} - ${song} | Free Backing Track">
<meta name="twitter:description" content="Get free ${song} by ${artist} backing track, plus free tools to mute any part, slow down for practice, record yourself, more">
<meta name="twitter:image" content="${logoPath}">
<!-- Canonical URL -->
<link rel="canonical" href="${fullPath}" />
<!-- Structured Data (Schema.org) -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "MusicRecording",
"name": "${song}",
"byArtist": {
"@type": "MusicGroup",
"name": "${artist}"
},
"url": "${fullPath}",
"image": "${logoPath}"
}
</script>
<script>
window.jamtrack_data = {
id: "${id}",
plan_code: "${plan_code}",
slug: "${slug}",
artist: "${artist}",
song: "${song}",
location: "${location}"
}
</script>
</head>
<body>
<div id="root">${html}</div>
<script src="/js/client-hydrate.bundle.js"></script>
</body>
</html>`;
const ARTIST_DIR = path.join(OUTPUT_DIR, original_artist_slug);
if (!fs.existsSync(ARTIST_DIR)) {
fs.mkdirSync(ARTIST_DIR, { recursive: false });
}
const finalOutputPath = process.env.NODE_ENV === "development" ? `${name_slug}.html` : `${name_slug}.html`;
const outputFilePath = path.join(ARTIST_DIR, finalOutputPath);
fs.writeFileSync(outputFilePath, fullHtml);
console.log(`Generated: ${outputFilePath}`);
}
console.log("All pages generated!");
});
};
const generateArtistPages = async (render) => {
const rows = [];
const OUTPUT_DIR = path.join(__dirname, "..", "public", "backing-tracks");
if (!fs.existsSync(OUTPUT_DIR)) {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}
console.log("generatPages starting")
const TemplatePage = TemplatePageModule.default;
const songs_csv = await load_csv(csvFilePath);
fs.createReadStream(artistCsvFilePath)
.pipe(csv())
.on("data", (row) => rows.push(row))
.on("end", async () => {
console.log(`Processing ${rows.length} rows...`);
for (const row of rows) {
const { original_artist, original_artist_slug, url } = row;
const artist = original_artist;
const matchingSongs = collect_songs_for_artist(original_artist_slug, songs_csv);
console.log(`Found ${matchingSongs.length} songs for ${artist}`);
const location = `/backing-tracks/${original_artist_slug}`;
const fullPath = process.env.REACT_APP_BASE_URL + location;
const logoPath = process.env.REACT_APP_BASE_URL + "/favicon.svg";
add_artist_to_sitemap(original_artist_slug);
console.log(`Generating ${artist}`);
const songs = matchingSongs.map((song) => {
return {
name: song.name,
plan_code: song.plan_code,
url: process.env.REACT_APP_BASE_URL + "/backing-tracks/" + song.original_artist_slug + "/" + song.name_slug
}
});
const html = render
? ReactDOMServer.renderToStaticMarkup(
React.createElement(ArtistTemplatePage, { artist, original_artist_slug, location })
)
: "";
const fullHtml = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="shortcut icon" href="/favicon.svg">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${artist} - Free Backing Track</title>
<link rel="stylesheet" href="${process.env.REACT_APP_BASE_URL}/css/theme.css">
<meta name="description" content="Get a free ${artist} backing track, plus free tools to mute any part, slow down for practice, record yourself, more">
<meta name="keywords" content="Backing Track, ${artist}, Instrumental">
<meta name="author" content="JamKazam">
<!-- Open Graph (Facebook, LinkedIn, etc.) -->
<meta property="og:title" content="${artist} | Free Backing Track">
<meta property="og:description" content="Get a free ${artist} backing track, plus free tools to mute any part, slow down for practice, record yourself, more">
<meta property="og:image" content="${logoPath}">
<meta property="og:url" content="${fullPath}">
<meta property="og:type" content="music.song">
<!-- Twitter Cards -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="${artist} | Free Backing Track">
<meta name="twitter:description" content="Get a free ${artist} backing track, plus free tools to mute any part, slow down for practice, record yourself, more">
<meta name="twitter:image" content="${logoPath}">
<!-- Canonical URL -->
<link rel="canonical" href="${fullPath}" />
<script>
window.jamtrack_data = {
artist: "${artist}",
original_artist_slug: "${original_artist_slug}",
location: "${location}",
songs: ${JSON.stringify(songs)}
}
</script>
</head>
<body>
<div id="root">${html}</div>
<script src="/js/client-hydrate.bundle.js"></script>
</body>
</html>`;
const finalOutputPath = process.env.NODE_ENV === "development" ? `${original_artist_slug}.html` : `${original_artist_slug}.html`;
const outputFilePath = path.join(OUTPUT_DIR, finalOutputPath);
fs.writeFileSync(outputFilePath, fullHtml);
console.log(`Generated: ${outputFilePath}`);
}
close_sitemap();
console.log("All pages generated!");
});
};
let render = false;
if (process.argv.length > 2) {
render = process.argv[2] === "true" || process.argv[2] === "yes" || process.argv[2] === "1";
}
init()
generateSongPages(render);
generateArtistPages(render);

View File

@ -1,40 +0,0 @@
#!/bin/bash
# requires node 22 at least
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
# default NODE_ENV to development if not set
if [ -z "$NODE_ENV" ]; then
NODE_ENV=development
fi
# default ENVIRONMENT to development if not set
if [ -z "$ENVIRONMENT" ]; then
ENVIRONMENT=development
fi
set -eo pipefail
export NODE_ENV
export ENVIRONMENT
echo "cleaning"
rm -rf $SCRIPT_DIR/build
echo "creating build dir - this is for correct image resolution; ideally this wouldn't be needed"
#mkdir -p $SCRIPT_DIR/build/assets/img
#cp -r $SCRIPT_DIR/../src/assets/img/* $SCRIPT_DIR/build/assets/img/
echo "creating client-hydrate.bundle.js for jamtrack landing pages"
# PUBLIC_URL=? for server builds
# NODE_ENV=production for server builds
npx webpack
#cp -r public/* output/
npm run build
echo "run generate.js for all jamtracks defined in the CSV"
NODE_ENV=$NODE_ENV ENVIRONMENT=$ENVIRONMENT npm run generate-song-landing-pages

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More