diff --git a/admin/Gemfile b/admin/Gemfile index 19ecfa7ef..7fc960e3b 100644 --- a/admin/Gemfile +++ b/admin/Gemfile @@ -34,6 +34,7 @@ end gem 'will_paginate', '3.0.3' gem 'bootstrap-will_paginate', '0.0.6' gem 'carrierwave', '0.9.0' +gem 'carrierwave_direct' gem 'uuidtools', '2.1.2' gem 'bcrypt-ruby', '3.0.1' gem 'jquery-rails', '2.3.0' # pinned because jquery-ui-rails was split from jquery-rails, but activeadmin doesn't support this gem yet diff --git a/admin/app/admin/promo_buzz.rb b/admin/app/admin/promo_buzz.rb new file mode 100644 index 000000000..e3d0035b1 --- /dev/null +++ b/admin/app/admin/promo_buzz.rb @@ -0,0 +1,67 @@ +ActiveAdmin.register JamRuby::PromoBuzz, :as => 'Buzz' do + + menu :label => 'Home Page Buzz' + + config.sort_order = 'position ASC aasm_state DESC updated_at DESC' + config.batch_actions = false + # config.clear_action_items! + config.filters = false + + form :partial => 'form' + + index do + column 'Short Text' do |pp| pp.text_short end + column 'Image' do |pp| + image_tag(pp.image_url, :size => '50x50') + end + column 'Long Text' do |pp| pp.text_long[0..256] end + column 'State' do |pp| pp.aasm_state end + column 'Position' do |pp| pp.position end + column 'Updated' do |pp| pp.updated_at end + default_actions + end + + show do + attributes_table do + row :text_short + row :text_long + row :image do |obj| + image_tag(obj.image_url, :size => '50x50') + end + row 'State' do |obj| obj.aasm_state end + row 'Position' do |obj| obj.position end + row 'Updated' do |obj| obj.updated_at end + end + end + + controller do + + def new + @promo = JamRuby::PromoBuzz.new + @promo.key = params[:key] if params[:key].present? + @promo.aasm_state = 'active' + @uploader = @promo.image + @uploader.success_action_redirect = new_admin_buzz_url + super + end + + def create + promo = PromoBuzz.create_with_params(params[:jam_ruby_promo_buzz]) + super + end + + def edit + @promo = resource + @promo.key = params[:key] if params[:key].present? && params[:key] != @promo.key + @uploader = @promo.image + @uploader.success_action_redirect = edit_admin_buzz_url(@promo) + super + end + + def update + super + end + + end + +end diff --git a/admin/app/admin/promo_latest.rb b/admin/app/admin/promo_latest.rb new file mode 100644 index 000000000..d846ec630 --- /dev/null +++ b/admin/app/admin/promo_latest.rb @@ -0,0 +1,52 @@ +ActiveAdmin.register JamRuby::PromoLatest, :as => 'Latest' do + + menu :label => 'Home Page Latest' + + config.sort_order = 'position ASC aasm_state DESC updated_at DESC' + config.batch_actions = false + # config.clear_action_items! + config.filters = false + + form :partial => 'form' + + index do + column 'State' do |pp| pp.aasm_state end + column 'Position' do |pp| pp.position end + column 'Updated' do |pp| pp.updated_at end + default_actions + end + + show do + attributes_table do + row 'State' do |obj| obj.aasm_state end + row 'Position' do |obj| obj.position end + row 'Updated' do |obj| obj.updated_at end + end + end + + controller do + + def new + @promo = JamRuby::PromoBuzz.new + @promo.aasm_state = 'active' + super + end + + def create + promo = PromoBuzz.create_with_params(params[:jam_ruby_promo_latest]) + super + end + + def edit + @promo = resource + super + end + + def update + super + end + + end + + +end diff --git a/admin/app/admin/user_progression.rb b/admin/app/admin/user_progression.rb index 5f6e12ec0..ab8f73c84 100644 --- a/admin/app/admin/user_progression.rb +++ b/admin/app/admin/user_progression.rb @@ -1,5 +1,5 @@ ActiveAdmin.register JamRuby::User, :as => 'User Progression' do - DATE_FORMAT = '%Y-%m-%d %H:%M' + PROGRESSION_DATE = '%Y-%m-%d %H:%M' unless defined?(PROGRESSION_DATE) menu :label => 'User Progression' @@ -10,69 +10,69 @@ ActiveAdmin.register JamRuby::User, :as => 'User Progression' do index do column :email do |user| link_to(truncate(user.email, {:length => 12}), resource_path(user), {:title => "#{user.first_name} #{user.last_name} (#{user.email})"}) end - column :updated_at do |uu| uu.updated_at.strftime(DATE_FORMAT) end - column :created_at do |uu| uu.created_at.strftime(DATE_FORMAT) end + column :updated_at do |uu| uu.updated_at.strftime(PROGRESSION_DATE) end + column :created_at do |uu| uu.created_at.strftime(PROGRESSION_DATE) end column :city column :musician column 'Client DL' do |uu| if dd = uu.first_downloaded_client_at - dd.strftime(DATE_FORMAT) + dd.strftime(PROGRESSION_DATE) else '' end end column 'Client Run' do |uu| if dd = uu.first_ran_client_at - dd.strftime(DATE_FORMAT) + dd.strftime(PROGRESSION_DATE) else '' end end column 'Certified Gear' do |uu| if dd = uu.first_certified_gear_at - dd.strftime(DATE_FORMAT) + dd.strftime(PROGRESSION_DATE) else '' end end column 'Any Session' do |uu| if dd = uu.first_music_session_at - dd.strftime(DATE_FORMAT) + dd.strftime(PROGRESSION_DATE) else '' end end column 'Real Session' do |uu| if dd = uu.first_real_music_session_at - dd.strftime(DATE_FORMAT) + dd.strftime(PROGRESSION_DATE) else '' end end column 'Good Session' do |uu| if dd = uu.first_good_music_session_at - dd.strftime(DATE_FORMAT) + dd.strftime(PROGRESSION_DATE) else '' end end column 'Invited' do |uu| if dd = uu.first_invited_at - dd.strftime(DATE_FORMAT) + dd.strftime(PROGRESSION_DATE) else '' end end column 'Friended' do |uu| if dd = uu.first_friended_at - dd.strftime(DATE_FORMAT) + dd.strftime(PROGRESSION_DATE) else '' end end column 'Promoted' do |uu| if dd = uu.first_social_promoted_at - dd.strftime(DATE_FORMAT) + dd.strftime(PROGRESSION_DATE) else '' end diff --git a/admin/app/uploaders/image_uploader.rb b/admin/app/uploaders/image_uploader.rb new file mode 100644 index 000000000..bde053642 --- /dev/null +++ b/admin/app/uploaders/image_uploader.rb @@ -0,0 +1,14 @@ +# encoding: utf-8 + +class ImageUploader < CarrierWave::Uploader::Base + include CarrierWaveDirect::Uploader + + include CarrierWave::MimeTypes + process :set_content_type + + # Add a white list of extensions which are allowed to be uploaded. + def extension_white_list + %w(jpg jpeg gif png) + end + +end diff --git a/admin/app/views/admin/buzzs/_form.html.erb b/admin/app/views/admin/buzzs/_form.html.erb new file mode 100644 index 000000000..96d6b7b83 --- /dev/null +++ b/admin/app/views/admin/buzzs/_form.html.erb @@ -0,0 +1,20 @@ +<% unless @promo.image_name.present? %> + <%= direct_upload_form_for @uploader do |f| %> +

<%= f.file_field :image %>

+

<%= f.submit "Upload Image" %>

+ <% end %> +<% end %> +<%= semantic_form_for([:admin, @promo], :html => {:multipart => true}, :url => @promo.new_record? ? admin_buzzs_path : "/admin/buzzs/#{@promo.id}") do |f| %> + <%= f.inputs do %> + <%= f.input(:text_short, :label => "Short Text", :input_html => {:maxlength => 512}) %> + <%= f.input(:text_long, :label => "Long Text", :input_html => {:rows => 3, :maxlength => 4096}) %> + <%= f.input(:position, :label => "Position", :input_html => {:maxlength => 4}) %> + <%= f.input(:aasm_state, :as => :select, :collection => Promotional::STATES, :label => 'Status') %> + Image File: <%= @promo.image_name %> + <%= f.hidden_field :key %> + <% # = f.input(:photo, :as => :file, :hint => f.template.image_tag(@promo.image_url(:thumb), :size => '50x50')) if @promo.new_record? %> + <% end %> + <% if @promo.image_name.present? %> + <%= f.actions %> + <% end %> +<% end %> diff --git a/admin/app/views/admin/latests/_form.html.erb b/admin/app/views/admin/latests/_form.html.erb new file mode 100644 index 000000000..b05d0140e --- /dev/null +++ b/admin/app/views/admin/latests/_form.html.erb @@ -0,0 +1,7 @@ +<%= semantic_form_for([:admin, @promo], :html => {:multipart => true}, :url => @promo.new_record? ? admin_latests_path : "/admin/latests/#{@promo.id}") do |f| %> + <%= f.inputs do %> + <%= f.input(:position, :label => "Position", :input_html => {:maxlength => 4}) %> + <%= f.input(:aasm_state, :as => :select, :collection => Promotional::STATES, :label => 'Status') %> + <% end %> + <%= f.actions %> +<% end %> diff --git a/admin/config/application.rb b/admin/config/application.rb index 92b12cdd3..f3b218211 100644 --- a/admin/config/application.rb +++ b/admin/config/application.rb @@ -76,7 +76,8 @@ module JamAdmin config.assets.precompile += ['active_admin.css', 'active_admin.js', 'active_admin/print.css'] # set to false to instead use amazon. You will also need to supply amazon secrets - config.store_artifacts_to_disk = true + config.store_artifacts_to_disk = false + config.storage_type = :fog # these only need to be set if store_artifact_to_files = false config.aws_artifact_access_key_id = ENV['AWS_KEY'] @@ -85,5 +86,8 @@ module JamAdmin config.aws_artifact_bucket_public = 'jamkazam-dev-public' config.aws_artifact_bucket = 'jamkazam-dev' config.aws_artifact_cache = '315576000' + + # for carrierwave_direct + config.action_controller.allow_forgery_protection = false end end diff --git a/admin/config/initializers/jam_ruby/promotional.rb b/admin/config/initializers/jam_ruby/promotional.rb new file mode 100644 index 000000000..7d58bf09d --- /dev/null +++ b/admin/config/initializers/jam_ruby/promotional.rb @@ -0,0 +1,3 @@ +class JamRuby::PromoBuzz < JamRuby::Promotional + mount_uploader :image, ImageUploader +end diff --git a/admin/config/routes.rb b/admin/config/routes.rb index ebc1b9790..b2b66d95e 100644 --- a/admin/config/routes.rb +++ b/admin/config/routes.rb @@ -1,3 +1,5 @@ +require 'resque/server' + JamAdmin::Application.routes.draw do # ActiveAdmin::Devise.config, @@ -12,6 +14,8 @@ JamAdmin::Application.routes.draw do match '/api/artifacts' => 'artifacts#update_artifacts', :via => :post + mount Resque::Server.new, :at => "/resque" + # The priority is based upon order of creation: # first created -> highest priority. diff --git a/db/manifest b/db/manifest index 6ab5685bc..f480dea41 100755 --- a/db/manifest +++ b/db/manifest @@ -85,3 +85,4 @@ discardable_recorded_tracks.sql music_sessions_have_claimed_recording.sql discardable_recorded_tracks2.sql icecast.sql +home_page_promos.sql diff --git a/db/up/home_page_promos.sql b/db/up/home_page_promos.sql new file mode 100644 index 000000000..9c0419b34 --- /dev/null +++ b/db/up/home_page_promos.sql @@ -0,0 +1,25 @@ +-- +CREATE TABLE promotionals( + id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(), + + /* allows for single table inheritance */ + type VARCHAR(128) NOT NULL DEFAULT 'JamRuby::PromoBuzz', + /* state machine */ + aasm_state VARCHAR(64) DEFAULT 'hidden', + /* order of promo within its types */ + position integer NOT NULL DEFAULT 0, + /* standard AR timestamps */ + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + + /* references latest recording or session polymorphically */ + latest_id VARCHAR(64) DEFAULT NULL, + latest_type VARCHAR(128) DEFAULT NULL, + + /* used for buzz promo type */ + image VARCHAR(1024) DEFAULT NULL, + text_short VARCHAR(512) DEFAULT NULL, + text_long VARCHAR(4096) DEFAULT NULL +); + +CREATE INDEX promo_latest_idx ON promotionals(latest_id, latest_type); diff --git a/db/up/mix_job_watch.sql b/db/up/mix_job_watch.sql new file mode 100644 index 000000000..e69de29bb diff --git a/ruby/Gemfile b/ruby/Gemfile index 67494b693..a8b11947f 100644 --- a/ruby/Gemfile +++ b/ruby/Gemfile @@ -42,6 +42,7 @@ group :test do gem 'spork', '0.9.0' gem 'database_cleaner', '0.7.0' gem 'rest-client' + gem 'faker' end # Specify your gem's dependencies in jam_ruby.gemspec diff --git a/ruby/lib/jam_ruby.rb b/ruby/lib/jam_ruby.rb index a9b28bb59..41885bfcf 100755 --- a/ruby/lib/jam_ruby.rb +++ b/ruby/lib/jam_ruby.rb @@ -86,6 +86,7 @@ require "jam_ruby/models/mix" require "jam_ruby/models/claimed_recording" require "jam_ruby/models/crash_dump" require "jam_ruby/models/isp_score_batch" +require "jam_ruby/models/promotional" require "jam_ruby/models/icecast_admin_authentication" require "jam_ruby/models/icecast_directory" require "jam_ruby/models/icecast_limit" diff --git a/ruby/lib/jam_ruby/models/promotional.rb b/ruby/lib/jam_ruby/models/promotional.rb new file mode 100644 index 000000000..7cecf0ac8 --- /dev/null +++ b/ruby/lib/jam_ruby/models/promotional.rb @@ -0,0 +1,66 @@ +class JamRuby::Promotional < ActiveRecord::Base + self.table_name = :promotionals + + attr_accessible :expires_at, :position, :aasm_state + + include AASM + HIDDEN_STATE = :hidden + ACTIVE_STATE = :active + EXPIRED_STATE = :expired + STATES = [HIDDEN_STATE, ACTIVE_STATE, EXPIRED_STATE] + + aasm do + state HIDDEN_STATE, :initial => true + state ACTIVE_STATE + state EXPIRED_STATE + + event :activate do + transitions :from => [HIDDEN_STATE, EXPIRED_STATE], :to => ACTIVE_STATE + end + + event :expire do + transitions :from => [HIDDEN_STATE, ACTIVE_STATE], :to => EXPIRED_STATE + end + + event :hide do + transitions :from => [HIDDEN_STATE, ACTIVE_STATE], :to => HIDDEN_STATE + end + + end + + def state + aasm_state + end + +end + +class JamRuby::PromoBuzz < JamRuby::Promotional + attr_accessible :image, :text_short, :text_long + + def self.create_with_params(params) + obj = self.new + obj.text_short = params[:text_short] + obj.text_long = params[:text_long] + obj.save! + obj + end + + def admin_title + "Buzz #{created_at.strftime('%Y-%m-%d %H-%M')}" + end + + def image_name + fn = image ? image.path || image.filename : nil + File.basename(fn) if fn + end + + def image_url + self.image.direct_fog_url(with_path: true) + end + +end + +class JamRuby::PromoLatest < JamRuby::Promotional + belongs_to :latest, :polymorphic => true + +end diff --git a/ruby/lib/jam_ruby/resque/audiomixer.rb b/ruby/lib/jam_ruby/resque/audiomixer.rb index 8bb0f5aa3..44f75436c 100644 --- a/ruby/lib/jam_ruby/resque/audiomixer.rb +++ b/ruby/lib/jam_ruby/resque/audiomixer.rb @@ -21,17 +21,35 @@ module JamRuby def validate raise "no files specified" if !@manifest[:files] || @manifest[:files].length == 0 + + @manifest[:files].each do |file| + codec = file[:codec] + raise "no codec specified" unless codec + + offset = file[:offset] + raise "no offset specified" unless offset + + filename = file[:filename] + raise "no filename specified" unless filename + end + + raise "no output specified" unless @manifest[:output] + raise "no output codec specified" unless @manifest[:output][:codec] + raise "no output filename specified" unless @manifest[:output][:filename] + + raise "no timeline specified" if !@manifest[:timeline] || @manifest[:timeline].length == 0 + + @manifest[:timeline].each do |entry| + + end end def fetch_audio_files - @manifest[:files].each do |file| - filename = file[:filename] - end end def run(manifest) - @manifest = manifest.symbolize_keys + @manifest = symbolize_keys(manifest) validate @@ -42,7 +60,14 @@ module JamRuby f.write(@manifest.to_json) end - #{"files": [{"codec": "vorbis", "offset": 0, "filename": "TPD - bass.flac-stereo.ogg"}, {"codec": "vorbis", "offset": 0, "filename": "TPD - bg vox.flac-stereo.ogg"}, {"codec": "vorbis", "offset": 0, "filename": "TPD - drums.flac-stereo.ogg"}, {"codec": "vorbis", "offset": 0, "filename": "TPD - guitars.flac-stereo.ogg"}, {"codec": "vorbis", "offset": 0, "filename": "TPD - lead vox.flac-stereo.ogg"}], "output": {"codec": "vorbis", "filename": "mix.ogg"}, "timeline": [{"timestamp": 0, "mix": [{"balance": 0, "level": 100}, {"balance": 0, "level": 100}, {"balance": 0, "level": 100}, {"balance": 0, "level": 100}, {"balance": 0, "level": 100}]}]} + #{"files": [{"codec": "vorbis", "offset": 0, "filename": "TPD - bass.flac-stereo.ogg"}, + # {"codec": "vorbis", "offset": 0, "filename": "TPD - bg vox.flac-stereo.ogg"}, + # {"codec": "vorbis", "offset": 0, "filename": "TPD - drums.flac-stereo.ogg"}, + # {"codec": "vorbis", "offset": 0, "filename": "TPD - guitars.flac-stereo.ogg"}, + # {"codec": "vorbis", "offset": 0, "filename": "TPD - lead vox.flac-stereo.ogg"}], + # "output": {"codec": "vorbis", "filename": "mix.ogg"}, + # "timeline": + # [{"timestamp": 0, "mix": [{"balance": 0, "level": 100}, {"balance": 0, "level": 100}, {"balance": 0, "level": 100}, {"balance": 0, "level": 100}, {"balance": 0, "level": 100}]}]} audiomixer_cmd = "#{APP_CONFIG.audiomixer_path} #{manifest_file}" @@ -52,6 +77,39 @@ module JamRuby system(audiomixer_cmd) end + def symbolize_keys(obj) + case obj + when Array + obj.inject([]){|res, val| + res << case val + when Hash, Array + symbolize_keys(val) + else + val + end + res + } + when Hash + obj.inject({}){|res, (key, val)| + nkey = case key + when String + key.to_sym + else + key + end + nval = case val + when Hash, Array + symbolize_keys(val) + else + val + end + res[nkey] = nval + res + } + else + obj + end + end end end \ No newline at end of file diff --git a/ruby/spec/factories.rb b/ruby/spec/factories.rb index 031dca330..23043fcdf 100644 --- a/ruby/spec/factories.rb +++ b/ruby/spec/factories.rb @@ -1,3 +1,5 @@ +require 'faker' + FactoryGirl.define do factory :user, :class => JamRuby::User do sequence(:email) { |n| "person_#{n}@example.com"} @@ -133,4 +135,9 @@ FactoryGirl.define do sequence(:lng) { |n| [-78.85029, -122.4155311][(n-1).modulo(2)] } end + factory :promo_buzz, :class => JamRuby::PromoBuzz do + text_short Faker::Lorem.sentence + text_long Faker::Lorem.paragraphs(3).join("\n") + end + end diff --git a/ruby/spec/jam_ruby/resque/audiomixer_spec.rb b/ruby/spec/jam_ruby/resque/audiomixer_spec.rb index f01519dbe..9c4d8b909 100644 --- a/ruby/spec/jam_ruby/resque/audiomixer_spec.rb +++ b/ruby/spec/jam_ruby/resque/audiomixer_spec.rb @@ -11,8 +11,20 @@ describe AudioMixer do end it "no codec specified" do - expect{ audiomixer.run({ "files" => [ "offset" => 0, "filename" => "/some/path"] }) } + expect{ audiomixer.run({ "files" => [ {"offset" => 0, "filename" => "/some/path"} ] }) }.to raise_error("no codec specified") + end + + it "no offset specified" do + expect{ audiomixer.run({ "files" => [ {"codec" => "vorbis", "filename" => "/some/path"} ] }) }.to raise_error("no offset specified") + end + + it "no output specified" do + expect{ audiomixer.run({ "files" => [ {"codec" => "vorbis", "offset" => 0, "filename" => "/some/path"} ] }) }.to raise_error("no output specified") end end + + describe "fetch_audio_files" do + + end end diff --git a/web/config/application.rb b/web/config/application.rb index 6b4800a31..3f488df2a 100644 --- a/web/config/application.rb +++ b/web/config/application.rb @@ -105,8 +105,8 @@ include JamRuby config.websocket_gateway_connect_time_stale = 2 config.websocket_gateway_connect_time_expire = 5 else - config.websocket_gateway_connect_time_stale = 6 - config.websocket_gateway_connect_time_expire = 10 + config.websocket_gateway_connect_time_stale = 300 + config.websocket_gateway_connect_time_expire = 6000 end config.websocket_gateway_internal_debug = false config.websocket_gateway_port = 6767 @@ -116,7 +116,8 @@ include JamRuby # set this to false if you want to disable signups (lock down public user creation) config.signup_enabled = true - config.storage_type = :file # or :fog, if using AWS + config.storage_type = :fog + # config.storage_type = :file # or :fog, if using AWS # these only used if storage_type = :fog config.aws_access_key_id = ENV['AWS_KEY']