Resolve conflicts
This commit is contained in:
commit
10687093c1
|
|
@ -37,7 +37,8 @@ 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
|
||||
gem 'jquery-rails' # , '2.3.0' # pinned because jquery-ui-rails was split from jquery-rails, but activeadmin doesn't support this gem yet
|
||||
gem 'jquery-ui-rails'
|
||||
gem 'rails3-jquery-autocomplete'
|
||||
gem 'activeadmin', '0.6.2'
|
||||
gem 'mime-types', '1.25'
|
||||
|
|
@ -48,7 +49,8 @@ gem 'country-select'
|
|||
gem 'aasm', '3.0.16'
|
||||
gem 'postgres-copy', '0.6.0'
|
||||
gem 'aws-sdk', '1.29.1'
|
||||
gem 'bugsnag'
|
||||
gem 'bugsnag'
|
||||
gem 'gon'
|
||||
gem 'resque'
|
||||
gem 'resque-retry'
|
||||
gem 'resque-failed-job-mailer'
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ ActiveAdmin.register JamRuby::CrashDump, :as => 'Crash Dump' do
|
|||
filter :timestamp
|
||||
filter :user_email, :as => :string
|
||||
filter :client_id
|
||||
menu :parent => 'Debug'
|
||||
|
||||
index do
|
||||
column "Timestamp" do |post|
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
ActiveAdmin.register JamRuby::Mix, :as => 'Errored Mixes' do
|
||||
|
||||
config.filters = true
|
||||
config.per_page = 50
|
||||
config.clear_action_items!
|
||||
config.sort_order = "created_at_desc"
|
||||
menu :parent => 'Sessions'
|
||||
|
||||
controller do
|
||||
|
||||
def scoped_collection
|
||||
Mix.where('error_reason is not NULL and completed = FALSE')
|
||||
end
|
||||
|
||||
def mix_again
|
||||
@mix = Mix.find(params[:id])
|
||||
@mix.enqueue
|
||||
render :json => {}
|
||||
end
|
||||
end
|
||||
|
||||
index :as => :block do |mix|
|
||||
div :for => mix do
|
||||
h3 "Mix (Users: #{mix.recording.users.map { |u| u.name }.join ','}) (When: #{mix.created_at.strftime('%b %d %Y, %H:%M')})"
|
||||
columns do
|
||||
column do
|
||||
panel 'Mix Details' do
|
||||
attributes_table_for(mix) do
|
||||
row :recording do |mix| auto_link(mix.recording, mix.recording.id) end
|
||||
row :created_at do |mix| mix.created_at.strftime('%b %d %Y, %H:%M') end
|
||||
row :s3_url do |mix| mix.url end
|
||||
row :manifest do |mix| mix.manifest end
|
||||
row :completed do |mix| "#{mix.completed ? "finished" : "not finished"}" end
|
||||
if mix.completed
|
||||
row :completed_at do |mix| mix.completed_at.strftime('%b %d %Y, %H:%M') end
|
||||
elsif mix.error_count > 0
|
||||
row :error_count do |mix| "#{mix.error_count} times failed" end
|
||||
row :error_reason do |mix| "last reason failed: #{mix.error_reason}" end
|
||||
row :error_detail do |mix| "last error detail: #{mix.error_detail}" end
|
||||
row :mix_again do |mix| div :class => 'mix-again' do
|
||||
span do link_to "Mix Again", '#', :class => 'mix-again', :'data-mix-id' => mix.id end
|
||||
span do div :class => 'mix-again-dialog' do end end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -2,4 +2,6 @@ ActiveAdmin.register JamRuby::IspScoreBatch, :as => 'Isp Score Data' do
|
|||
|
||||
config.sort_order = 'created_at_desc'
|
||||
|
||||
menu :parent => 'Debug'
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
ActiveAdmin.register JamRuby::InvitedUser, :as => 'Invited Users' do
|
||||
menu :label => 'Invite Users'
|
||||
menu :label => 'Invite', :parent => 'Users'
|
||||
|
||||
config.sort_order = 'created_at'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
ActiveAdmin.register JamRuby::User, :as => 'Users' do
|
||||
|
||||
menu :label => 'Jam User'
|
||||
menu :label => 'Users', :parent => 'Users'
|
||||
|
||||
config.sort_order = 'created_at DESC'
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
ActiveAdmin.register JamRuby::Mix, :as => 'Mixes' do
|
||||
|
||||
config.filters = true
|
||||
config.per_page = 50
|
||||
config.clear_action_items!
|
||||
config.sort_order = "created_at_desc"
|
||||
menu :parent => 'Sessions'
|
||||
|
||||
controller do
|
||||
|
||||
def mix_again
|
||||
@mix = Mix.find(params[:id])
|
||||
@mix.enqueue
|
||||
render :json => {}
|
||||
end
|
||||
end
|
||||
|
||||
index :as => :block do |mix|
|
||||
div :for => mix do
|
||||
h3 "Mix (Users: #{mix.recording.users.map { |u| u.name }.join ','}) (When: #{mix.created_at.strftime('%b %d %Y, %H:%M')})"
|
||||
columns do
|
||||
column do
|
||||
panel 'Mix Details' do
|
||||
attributes_table_for(mix) do
|
||||
row :recording do |mix| auto_link(mix.recording, mix.recording.id) end
|
||||
row :created_at do |mix| mix.created_at.strftime('%b %d %Y, %H:%M') end
|
||||
row :s3_url do |mix| mix.url end
|
||||
row :manifest do |mix| mix.manifest end
|
||||
row :completed do |mix| "#{mix.completed ? "finished" : "not finished"}" end
|
||||
if mix.completed
|
||||
row :completed_at do |mix| mix.completed_at.strftime('%b %d %Y, %H:%M') end
|
||||
elsif mix.error_count > 0
|
||||
row :error_count do |mix| "#{mix.error_count} times failed" end
|
||||
row :error_reason do |mix| "last reason failed: #{mix.error_reason}" end
|
||||
row :error_detail do |mix| "last error detail: #{mix.error_detail}" end
|
||||
row :mix_again do |mix| div :class => 'mix-again' do
|
||||
span do link_to "Mix Again", '#', :class => 'mix-again', :'data-mix-id' => mix.id end
|
||||
span do div :class => 'mix-again-dialog' do end end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
ActiveAdmin.register JamRuby::MusicSessionHistory, :as => 'Music Session History', :sort_order => 'created_at DESC' do
|
||||
ActiveAdmin.register JamRuby::MusicSessionHistory, :as => 'Music Session History' do
|
||||
|
||||
config.filters = false
|
||||
config.per_page = 50
|
||||
config.clear_action_items!
|
||||
config.sort_order = 'created_at_desc'
|
||||
menu :parent => 'Sessions', :label => 'Sessions'
|
||||
|
||||
controller do
|
||||
def scoped_collection
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
ActiveAdmin.register JamRuby::PromoBuzz, :as => 'Buzz' do
|
||||
|
||||
menu :label => 'Home Page Buzz'
|
||||
menu :label => 'Buzz', :parent => 'Home Page'
|
||||
|
||||
config.sort_order = 'position ASC aasm_state DESC updated_at DESC'
|
||||
config.batch_actions = false
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
ActiveAdmin.register JamRuby::PromoLatest, :as => 'Latest' do
|
||||
|
||||
menu :label => 'Home Page Latest'
|
||||
menu :label => 'Latest', :parent => 'Home Page'
|
||||
|
||||
config.batch_actions = false
|
||||
config.sort_order = ''
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
ActiveAdmin.register JamRuby::User do
|
||||
# define routes for "autocomplete :admin_user, :email"
|
||||
collection_action :autocomplete_user_email, :method => :get
|
||||
|
||||
controller do
|
||||
autocomplete :invited_user, :email
|
||||
end
|
||||
end
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
ActiveAdmin.register JamRuby::User, :as => 'User Progression' do
|
||||
PROGRESSION_DATE = '%Y-%m-%d %H:%M' unless defined?(PROGRESSION_DATE)
|
||||
|
||||
menu :label => 'User Progression'
|
||||
menu :label => 'Progression', :parent => 'Users'
|
||||
|
||||
config.sort_order = 'updated_at DESC'
|
||||
config.batch_actions = false
|
||||
|
|
|
|||
|
|
@ -1,2 +1,11 @@
|
|||
//= require active_admin/base
|
||||
//= require autocomplete-rails
|
||||
// //= require active_admin/base
|
||||
//= require jquery
|
||||
//= require jquery_ujs
|
||||
//= require jquery.ui.core
|
||||
//= require jquery.ui.widget
|
||||
//= require jquery.ui.datepicker
|
||||
//= require jquery.ui.dialog
|
||||
//= require active_admin/application
|
||||
//= require autocomplete-rails
|
||||
//= require base
|
||||
//= require_tree .
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
(function(context,$) {
|
||||
|
||||
/**
|
||||
* Javascript wrappers for the REST API
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
context.JK = context.JK || {};
|
||||
context.JK.RestAdmin = function() {
|
||||
|
||||
var self = this;
|
||||
var logger = context.JK.logger;
|
||||
|
||||
function tryMixAgain(options) {
|
||||
var mixId = options['mix_id']
|
||||
return $.ajax({
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
url: gon.global.prefix + 'api/mix/' + mixId + '/enqueue',
|
||||
contentType: 'application/json',
|
||||
processData: false
|
||||
});
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
return self;
|
||||
}
|
||||
|
||||
// Expose publics
|
||||
this.initialize = initialize;
|
||||
this.tryMixAgain = tryMixAgain;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
})(window,jQuery);
|
||||
|
|
@ -12,4 +12,3 @@
|
|||
//
|
||||
//= require jquery
|
||||
//= require jquery_ujs
|
||||
//= require_tree .
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
(function(context,$) {
|
||||
|
||||
context.JK = {}
|
||||
|
||||
var console_methods = [
|
||||
'log', 'debug', 'info', 'warn', 'error', 'assert',
|
||||
'clear', 'dir', 'dirxml', 'trace', 'group',
|
||||
'groupCollapsed', 'groupEnd', 'time', 'timeEnd',
|
||||
'timeStamp', 'profile', 'profileEnd', 'count',
|
||||
'exception', 'table'
|
||||
];
|
||||
|
||||
if ('undefined' === typeof(context.console)) {
|
||||
context.console = {};
|
||||
$.each(console_methods, function(index, value) {
|
||||
context.console[value] = $.noop;
|
||||
});
|
||||
}
|
||||
|
||||
context.JK.logger = context.console;
|
||||
|
||||
|
||||
})(window, jQuery);
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
(function(context,$) {
|
||||
|
||||
|
||||
var restAdmin = context.JK.RestAdmin();
|
||||
|
||||
$(function() {
|
||||
// convert mix again links to ajax
|
||||
$('a.mix-again').click(function() {
|
||||
var $link = $(this);
|
||||
restAdmin.tryMixAgain({mix_id: $link.attr('data-mix-id')})
|
||||
.done(function(response) {
|
||||
$link.closest('div.mix-again').find('div.mix-again-dialog').html('<div>Mix enqueued</div><a href="' + gon.global.prefix + 'resque">Resque Web</a>').dialog();
|
||||
})
|
||||
.error(function(jqXHR) {
|
||||
$link.closest('div.mix-again').find('div.mix-again-dialog').html('Mix failed: ' + jqXHR.responseText).dialog();
|
||||
})
|
||||
|
||||
return false;
|
||||
})
|
||||
|
||||
});
|
||||
})(window, jQuery);
|
||||
|
|
@ -7,6 +7,9 @@
|
|||
// For example, to change the sidebar width:
|
||||
// $sidebar-width: 242px;
|
||||
|
||||
/*
|
||||
*= require jquery.ui.all
|
||||
*/
|
||||
// Active Admin's got SASS!
|
||||
@import "active_admin/mixins";
|
||||
@import "active_admin/base";
|
||||
|
|
|
|||
|
|
@ -9,5 +9,6 @@
|
|||
* compiled file, but it's generally better to create a new file per style scope.
|
||||
*
|
||||
*= require_self
|
||||
*= require jquery.ui.all
|
||||
*= require_tree .
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
.version-info {
|
||||
font-size:small;
|
||||
color:lightgray;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
class ApplicationController < ActionController::Base
|
||||
protect_from_forgery
|
||||
|
||||
before_filter :prepare_gon
|
||||
|
||||
def prepare_gon
|
||||
gon.another = 'hello'
|
||||
gon.prefix = ENV['RAILS_RELATIVE_URL_ROOT'] || '/'
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ module JamAdmin
|
|||
# Activate observers that should always be running.
|
||||
config.active_record.observers = "JamRuby::InvitedUserObserver"
|
||||
|
||||
config.assets.prefix = ENV['RAILS_RELATIVE_URL_ROOT'] || '/'
|
||||
#config.assets.prefix = ENV['RAILS_RELATIVE_URL_ROOT'] || '/'
|
||||
|
||||
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
||||
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
||||
|
|
@ -80,14 +80,16 @@ module JamAdmin
|
|||
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']
|
||||
config.aws_artifact_secret_access_key = ENV['AWS_SECRET']
|
||||
config.aws_artifact_region = 'us-east-1'
|
||||
config.aws_artifact_bucket_public = 'jamkazam-dev-public'
|
||||
config.aws_artifact_bucket = 'jamkazam-dev'
|
||||
config.aws_artifact_cache = '315576000'
|
||||
config.aws_access_key_id = ENV['AWS_KEY']
|
||||
config.aws_secret_access_key = ENV['AWS_SECRET']
|
||||
config.aws_region = 'us-east-1'
|
||||
config.aws_bucket_public = 'jamkazam-dev-public'
|
||||
config.aws_bucket = 'jamkazam-dev'
|
||||
config.aws_cache = '315576000'
|
||||
|
||||
# for carrierwave_direct
|
||||
config.action_controller.allow_forgery_protection = false
|
||||
|
||||
config.redis_host = "localhost:6379"
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
# Load the rails application
|
||||
require File.expand_path('../application', __FILE__)
|
||||
|
||||
APP_CONFIG = Rails.application.config
|
||||
|
||||
# Initialize the rails application
|
||||
JamAdmin::Application.initialize!
|
||||
|
|
|
|||
|
|
@ -71,6 +71,6 @@ JamAdmin::Application.configure do
|
|||
# Show the logging configuration on STDOUT
|
||||
config.show_log_configuration = false
|
||||
|
||||
config.aws_artifact_bucket_public = 'jamkazam-public'
|
||||
config.aws_artifact_bucket = 'jamkazam'
|
||||
config.aws_bucket_public = 'jamkazam-public'
|
||||
config.aws_bucket = 'jamkazam'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ class Footer < ActiveAdmin::Component
|
|||
def build
|
||||
super(id: "footer")
|
||||
para "version info: web=#{::JamAdmin::VERSION} lib=#{JamRuby::VERSION} db=#{JamDb::VERSION}"
|
||||
render :inline => include_gon
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ CarrierWave.configure do |config|
|
|||
config.storage = :fog
|
||||
config.fog_credentials = {
|
||||
:provider => 'AWS',
|
||||
:aws_access_key_id => JamAdmin::Application.config.aws_artifact_access_key_id,
|
||||
:aws_secret_access_key => JamAdmin::Application.config.aws_artifact_secret_access_key,
|
||||
:region => JamAdmin::Application.config.aws_artifact_region,
|
||||
:aws_access_key_id => JamAdmin::Application.config.aws_access_key_id,
|
||||
:aws_secret_access_key => JamAdmin::Application.config.aws_secret_access_key,
|
||||
:region => JamAdmin::Application.config.aws_region,
|
||||
}
|
||||
config.fog_directory = JamAdmin::Application.config.aws_artifact_bucket_public # required
|
||||
config.fog_directory = JamAdmin::Application.config.aws_bucket_public # required
|
||||
config.fog_public = true # optional, defaults to true
|
||||
config.fog_attributes = {'Cache-Control'=>"max-age=#{JamAdmin::Application.config.aws_artifact_cache}"} # optional, defaults to {}
|
||||
config.fog_attributes = {'Cache-Control'=>"max-age=#{JamAdmin::Application.config.aws_cache}"} # optional, defaults to {}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
Gon.global.prefix = ENV['RAILS_RELATIVE_URL_ROOT'] || '/'
|
||||
|
|
@ -0,0 +1 @@
|
|||
Resque.redis = Rails.application.config.redis_host
|
||||
|
|
@ -15,6 +15,7 @@ JamAdmin::Application.routes.draw do
|
|||
ActiveAdmin.routes(self)
|
||||
|
||||
match '/api/artifacts' => 'artifacts#update_artifacts', :via => :post
|
||||
match '/api/mix/:id/enqueue' => 'admin/mixes#mix_again', :via => :post
|
||||
|
||||
mount Resque::Server.new, :at => "/resque"
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
desc 'Print out all defined routes in match order, with names. Target specific controller with CONTROLLER=x.'
|
||||
task custom_routes: :environment do
|
||||
require 'rails/application/route_inspector'
|
||||
|
||||
inspector = Rails::Application::RouteInspector.new
|
||||
puts inspector.format(Rails.application.routes.routes)
|
||||
|
||||
#all_routes = Rails.application.routes.routes
|
||||
|
||||
#inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes)
|
||||
#puts inspector.format(ActionDispatch::Routing::ConsoleFormatter.new, ENV['CONTROLLER'])
|
||||
end
|
||||
|
|
@ -86,4 +86,6 @@ music_sessions_have_claimed_recording.sql
|
|||
discardable_recorded_tracks2.sql
|
||||
icecast.sql
|
||||
home_page_promos.sql
|
||||
mix_job_watch.sql
|
||||
mix_job_watch.sql
|
||||
music_session_constraints.sql
|
||||
mixes_drop_manifest_add_retry.sql
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE mixes DROP COLUMN manifest;
|
||||
ALTER TABLE mixes ADD COLUMN should_retry BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
alter table music_sessions_comments drop constraint music_sessions_comments_music_session_id_fkey;
|
||||
alter table music_sessions_comments add constraint ms_comments_ms_history_fkey foreign key (music_session_id)
|
||||
references music_sessions_history(music_session_id) match simple
|
||||
ON UPDATE NO ACTION ON DELETE CASCADE;
|
||||
|
||||
alter table music_sessions_likers drop constraint music_sessions_likers_music_session_id_fkey;
|
||||
alter table music_sessions_likers add constraint ms_likers_ms_history_fkey foreign key (music_session_id)
|
||||
references music_sessions_history(music_session_id) match simple
|
||||
ON UPDATE NO ACTION ON DELETE CASCADE;
|
||||
|
|
@ -29,6 +29,7 @@ require "jam_ruby/lib/s3_util"
|
|||
require "jam_ruby/lib/s3_manager"
|
||||
require "jam_ruby/lib/profanity"
|
||||
require "jam_ruby/resque/audiomixer"
|
||||
require "jam_ruby/resque/scheduled/audiomixer_retry"
|
||||
require "jam_ruby/mq_router"
|
||||
require "jam_ruby/base_manager"
|
||||
require "jam_ruby/connection_manager"
|
||||
|
|
@ -64,6 +65,8 @@ require "jam_ruby/models/band_musician"
|
|||
require "jam_ruby/models/connection"
|
||||
require "jam_ruby/models/friendship"
|
||||
require "jam_ruby/models/music_session"
|
||||
require "jam_ruby/models/music_session_comment"
|
||||
require "jam_ruby/models/music_session_liker"
|
||||
require "jam_ruby/models/music_session_history"
|
||||
require "jam_ruby/models/music_session_user_history"
|
||||
require "jam_ruby/models/music_session_perf_data"
|
||||
|
|
@ -80,6 +83,9 @@ require "jam_ruby/models/user_follower"
|
|||
require "jam_ruby/models/user_following"
|
||||
require "jam_ruby/models/search"
|
||||
require "jam_ruby/models/recording"
|
||||
require "jam_ruby/models/recording_comment"
|
||||
require "jam_ruby/models/recording_liker"
|
||||
require "jam_ruby/models/recording_play"
|
||||
require "jam_ruby/models/recorded_track"
|
||||
require "jam_ruby/models/recorded_track_observer"
|
||||
require "jam_ruby/models/mix"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ module JamRuby
|
|||
|
||||
|
||||
def init
|
||||
#puts "Init self.client #{self.clients}"
|
||||
self.clients ||= 10000
|
||||
self.sources ||= 1000
|
||||
self.queue_size ||= 102400
|
||||
|
|
@ -36,4 +35,4 @@ module JamRuby
|
|||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,22 +9,40 @@ module JamRuby
|
|||
self.primary_key = 'id'
|
||||
belongs_to :recording, :class_name => "JamRuby::Recording", :inverse_of => :mixes
|
||||
|
||||
def self.schedule(recording, manifest)
|
||||
|
||||
|
||||
def self.schedule(recording)
|
||||
raise if recording.nil?
|
||||
raise if manifest.nil?
|
||||
|
||||
mix = Mix.new
|
||||
mix.recording = recording
|
||||
mix.manifest = manifest.to_json
|
||||
mix.save
|
||||
mix.url = construct_filename(recording.id, mix.id)
|
||||
mix.url = construct_filename(mix.created_at, recording.id, mix.id)
|
||||
if mix.save
|
||||
Resque.enqueue(AudioMixer, mix.id, mix.sign_put)
|
||||
mix.enqueue
|
||||
end
|
||||
|
||||
mix
|
||||
end
|
||||
|
||||
def enqueue
|
||||
begin
|
||||
Resque.enqueue(AudioMixer, self.id, self.sign_put)
|
||||
rescue
|
||||
# implies redis is down. we don't update started_at
|
||||
false
|
||||
end
|
||||
|
||||
Mix.where(:id => self.id).update_all(:started_at => Time.now)
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def can_download?(some_user)
|
||||
!ClaimedRecording.find_by_user_id_and_recording_id(some_user.id, recording_id).nil?
|
||||
end
|
||||
|
||||
|
||||
def errored(reason, detail)
|
||||
self.error_reason = reason
|
||||
self.error_detail = detail
|
||||
|
|
@ -44,8 +62,25 @@ module JamRuby
|
|||
end
|
||||
end
|
||||
|
||||
# valid for 1 day; because the s3 urls eventually expire
|
||||
def manifest
|
||||
one_day = 60 * 60 * 24
|
||||
|
||||
manifest = { "files" => [], "timeline" => [] }
|
||||
mix_params = []
|
||||
recording.recorded_tracks.each do |recorded_track|
|
||||
manifest["files"] << { "filename" => recorded_track.sign_url(one_day), "codec" => "vorbis", "offset" => 0 }
|
||||
mix_params << { "level" => 100, "balance" => 0 }
|
||||
end
|
||||
|
||||
manifest["timeline"] << { "timestamp" => 0, "mix" => mix_params }
|
||||
manifest["output"] = { "codec" => "vorbis" }
|
||||
manifest["recording_id"] = self.id
|
||||
manifest
|
||||
end
|
||||
|
||||
def s3_url
|
||||
s3_manager.s3_url(filename)
|
||||
s3_manager.s3_url(url)
|
||||
end
|
||||
|
||||
def is_completed
|
||||
|
|
@ -54,11 +89,17 @@ module JamRuby
|
|||
|
||||
def sign_url(expiration_time = 120)
|
||||
# expire link in 1 minute--the expectation is that a client is immediately following this link
|
||||
s3_manager.sign_url(filename, {:expires => expiration_time, :response_content_type => 'audio/ogg', :secure => false})
|
||||
s3_manager.sign_url(self.url, {:expires => expiration_time, :response_content_type => 'audio/ogg', :secure => false})
|
||||
end
|
||||
|
||||
def sign_put(expiration_time = 3600 * 24)
|
||||
s3_manager.sign_url(filename, {:expires => expiration_time, :content_type => 'audio/ogg', :secure => false}, :put)
|
||||
s3_manager.sign_url(self.url, {:expires => expiration_time, :content_type => 'audio/ogg', :secure => false}, :put)
|
||||
end
|
||||
|
||||
def self.queue_jobs_needing_retry
|
||||
Mix.find_each(:conditions => 'should_retry = TRUE or started_at is NULL', :batch_size => 100) do |mix|
|
||||
mix.enqueue
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
|
@ -69,14 +110,12 @@ module JamRuby
|
|||
|
||||
def filename
|
||||
# construct a path for s3
|
||||
Mix.construct_filename(self.recording.id, self.id)
|
||||
Mix.construct_filename(self.created_at, self.recording.id, self.id)
|
||||
end
|
||||
|
||||
def self.construct_filename(recording_id, id)
|
||||
def self.construct_filename(created_at, recording_id, id)
|
||||
raise "unknown ID" unless id
|
||||
"recordings/#{recording_id}/mix-#{id}.ogg"
|
||||
"recordings/#{created_at.strftime('%m-%d-%Y')}/#{recording_id}/mix-#{id}.ogg"
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ module JamRuby
|
|||
validate :creator_is_musician
|
||||
validate :no_new_playback_while_playing
|
||||
|
||||
|
||||
def creator_is_musician
|
||||
unless creator.musician?
|
||||
errors.add(:creator, ValidationMessages::MUST_BE_A_MUSICIAN)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
module JamRuby
|
||||
class MusicSessionComment < ActiveRecord::Base
|
||||
|
||||
self.table_name = "music_sessions_comments"
|
||||
|
||||
self.primary_key = 'id'
|
||||
|
||||
belongs_to :music_session, :class_name => "JamRuby::MusicSessionHistory", :foreign_key => "music_session_id"
|
||||
belongs_to :user, :class_name => "JamRuby::User", :foreign_key => "creator_id"
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -15,8 +15,19 @@ module JamRuby
|
|||
:foreign_key => :band_id,
|
||||
:inverse_of => :music_session_history)
|
||||
|
||||
has_many :comments, :class_name => "JamRuby::MusicSessionComment", :foreign_key => "music_session_id"
|
||||
has_many :likes, :class_name => "JamRuby::MusicSessionLiker", :foreign_key => "music_session_id"
|
||||
|
||||
GENRE_SEPARATOR = '|'
|
||||
|
||||
def comment_count
|
||||
self.comments.size
|
||||
end
|
||||
|
||||
def like_count
|
||||
self.likes.size
|
||||
end
|
||||
|
||||
def self.index(current_user, user_id, band_id = nil, genre = nil)
|
||||
hide_private = false
|
||||
if current_user.id != user_id
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
module JamRuby
|
||||
class MusicSessionLiker < ActiveRecord::Base
|
||||
|
||||
self.table_name = "music_sessions_likers"
|
||||
|
||||
self.primary_key = 'id'
|
||||
|
||||
belongs_to :music_session, :class_name => "JamRuby::MusicSessionHistory", :foreign_key => "music_session_id"
|
||||
belongs_to :user, :class_name => "JamRuby::User", :foreign_key => "liker_id"
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -86,13 +86,13 @@ module JamRuby
|
|||
recorded_track.next_part_to_upload = 0
|
||||
recorded_track.file_offset = 0
|
||||
recorded_track.save
|
||||
recorded_track.url = construct_filename(recording.id, track.client_track_id)
|
||||
recorded_track.url = construct_filename(recorded_track.created_at, recording.id, track.client_track_id)
|
||||
recorded_track.save
|
||||
recorded_track
|
||||
end
|
||||
|
||||
def sign_url(expiration_time = 120)
|
||||
s3_manager.sign_url(url, {:expires => expiration_time, :response_content_type => 'audio/ogg', :secure => false})
|
||||
s3_manager.sign_url(self.url, {:expires => expiration_time, :response_content_type => 'audio/ogg', :secure => false})
|
||||
end
|
||||
|
||||
def upload_start(length, md5)
|
||||
|
|
@ -128,7 +128,7 @@ module JamRuby
|
|||
end
|
||||
|
||||
def upload_sign(content_md5)
|
||||
s3_manager.upload_sign(filename, content_md5, next_part_to_upload, upload_id)
|
||||
s3_manager.upload_sign(url, content_md5, next_part_to_upload, upload_id)
|
||||
end
|
||||
|
||||
def upload_part_complete(part, offset)
|
||||
|
|
@ -154,17 +154,17 @@ module JamRuby
|
|||
private
|
||||
|
||||
def delete_s3_files
|
||||
s3_manager.delete(filename)
|
||||
s3_manager.delete(url)
|
||||
end
|
||||
|
||||
def filename
|
||||
# construct a path for s3
|
||||
RecordedTrack.construct_filename(self.recording.id, self.client_track_id)
|
||||
RecordedTrack.construct_filename(self.created_at, self.recording.id, self.client_track_id)
|
||||
end
|
||||
|
||||
def self.construct_filename(recording_id, client_track_id)
|
||||
def self.construct_filename(created_at, recording_id, client_track_id)
|
||||
raise "unknown ID" unless client_track_id
|
||||
"recordings/#{recording_id}/track-#{client_track_id}.ogg"
|
||||
"recordings/#{created_at.strftime('%m-%d-%Y')}/#{recording_id}/track-#{client_track_id}.ogg"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,17 +7,34 @@ module JamRuby
|
|||
|
||||
has_many :claimed_recordings, :class_name => "JamRuby::ClaimedRecording", :inverse_of => :recording
|
||||
has_many :users, :through => :recorded_tracks, :class_name => "JamRuby::User"
|
||||
has_many :mixes, :class_name => "JamRuby::Mix", :inverse_of => :recording
|
||||
has_many :recorded_tracks, :class_name => "JamRuby::RecordedTrack", :foreign_key => :recording_id
|
||||
has_many :comments, :class_name => "JamRuby::RecordingComment", :foreign_key => "recording_id"
|
||||
has_many :likes, :class_name => "JamRuby::RecordingLiker", :foreign_key => "recording_id"
|
||||
has_many :plays, :class_name => "JamRuby::RecordingPlay", :foreign_key => "recording_id"
|
||||
|
||||
belongs_to :owner, :class_name => "JamRuby::User", :inverse_of => :owned_recordings
|
||||
belongs_to :band, :class_name => "JamRuby::Band", :inverse_of => :recordings
|
||||
belongs_to :music_session, :class_name => "JamRuby::MusicSession", :inverse_of => :recordings
|
||||
has_many :mixes, :class_name => "JamRuby::Mix", :inverse_of => :recording
|
||||
has_many :recorded_tracks, :class_name => "JamRuby::RecordedTrack", :foreign_key => :recording_id
|
||||
|
||||
validates :music_session, :presence => true
|
||||
validate :not_already_recording, :on => :create
|
||||
validate :not_still_finalizing_previous, :on => :create
|
||||
validate :not_playback_recording, :on => :create
|
||||
validate :already_stopped_recording
|
||||
|
||||
def comment_count
|
||||
self.comments.size
|
||||
end
|
||||
|
||||
def like_count
|
||||
self.likes.size
|
||||
end
|
||||
|
||||
def play_count
|
||||
self.plays.size
|
||||
end
|
||||
|
||||
def not_already_recording
|
||||
if music_session.is_recording?
|
||||
errors.add(:music_session, ValidationMessages::ALREADY_BEING_RECORDED)
|
||||
|
|
@ -193,7 +210,7 @@ module JamRuby
|
|||
downloads.push(
|
||||
{
|
||||
:type => "mix",
|
||||
:id => mix.id,
|
||||
:id => mix.id.to_s,
|
||||
:recording_id => mix.recording_id,
|
||||
:length => mix.length,
|
||||
:md5 => mix.md5,
|
||||
|
|
@ -268,7 +285,7 @@ module JamRuby
|
|||
return unless recorded_track.fully_uploaded
|
||||
end
|
||||
|
||||
self.mixes << Mix.schedule(self, base_mix_manifest)
|
||||
self.mixes << Mix.schedule(self)
|
||||
|
||||
save
|
||||
end
|
||||
|
|
@ -293,21 +310,6 @@ module JamRuby
|
|||
end
|
||||
=end
|
||||
|
||||
def base_mix_manifest
|
||||
manifest = { "files" => [], "timeline" => [] }
|
||||
mix_params = []
|
||||
recorded_tracks.each do |recorded_track|
|
||||
return nil unless recorded_track.fully_uploaded
|
||||
manifest["files"] << { "filename" => recorded_track.sign_url(60 * 60 * 24), "codec" => "vorbis", "offset" => 0 }
|
||||
mix_params << { "level" => 100, "balance" => 0 }
|
||||
end
|
||||
|
||||
manifest["timeline"] << { "timestamp" => 0, "mix" => mix_params }
|
||||
manifest["output"] = { "codec" => "vorbis" }
|
||||
manifest["recording_id"] = self.id
|
||||
manifest
|
||||
end
|
||||
|
||||
private
|
||||
def self.validate_user_is_band_member(user, band)
|
||||
unless band.users.exists? user
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
module JamRuby
|
||||
class RecordingComment < ActiveRecord::Base
|
||||
|
||||
self.table_name = "recordings_comments"
|
||||
|
||||
self.primary_key = 'id'
|
||||
|
||||
belongs_to :recording, :class_name => "JamRuby::Recording", :foreign_key => "recording_id"
|
||||
belongs_to :user, :class_name => "JamRuby::User", :foreign_key => "creator_id"
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
module JamRuby
|
||||
class RecordingLiker < ActiveRecord::Base
|
||||
|
||||
self.table_name = "recordings_likers"
|
||||
|
||||
self.primary_key = 'id'
|
||||
|
||||
belongs_to :recording, :class_name => "JamRuby::Recording", :foreign_key => "recording_id"
|
||||
belongs_to :user, :class_name => "JamRuby::User", :foreign_key => "liker_id"
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
module JamRuby
|
||||
class RecordingPlay < ActiveRecord::Base
|
||||
|
||||
self.table_name = "recordings_plays"
|
||||
|
||||
self.primary_key = 'id'
|
||||
|
||||
belongs_to :recording, :class_name => "JamRuby::Recording", :foreign_key => "recording_id"
|
||||
belongs_to :user, :class_name => "JamRuby::User", :foreign_key => "player_id"
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -6,12 +6,11 @@ require 'digest/md5'
|
|||
|
||||
module JamRuby
|
||||
|
||||
# executes a mix of tracks, creating a final output mix
|
||||
class AudioMixer
|
||||
|
||||
@queue = :audiomixer
|
||||
|
||||
#extend Resque::Plugins::Retry
|
||||
|
||||
@@log = Logging.logger[AudioMixer]
|
||||
|
||||
attr_accessor :mix_id, :manifest, :manifest_file, :output_filename, :error_out_filename, :postback_output_url,
|
||||
|
|
@ -49,6 +48,7 @@ module JamRuby
|
|||
raise "no timeline specified" unless @manifest[:timeline]
|
||||
raise "no recording_id specified" unless @manifest[:recording_id]
|
||||
raise "no mix_id specified" unless @manifest[:mix_id]
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -79,9 +79,9 @@ module JamRuby
|
|||
@error_detail = "url #{filename}, error=#{e}"
|
||||
raise e
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@log.debug("downloaded #{download_filename}")
|
||||
filename = download_filename
|
||||
file[:filename] = download_filename
|
||||
end
|
||||
|
|
@ -103,7 +103,7 @@ module JamRuby
|
|||
# write the manifest object to file, to pass into audiomixer
|
||||
def prepare_manifest
|
||||
|
||||
@manifest_file = Dir::Tmpname.make_tmpname( ["#{Dir.tmpdir}/audiomixer-manifest-#{@manifest['recording_id']}", '.json'], nil)
|
||||
@manifest_file = Dir::Tmpname.make_tmpname( ["#{Dir.tmpdir}/audiomixer-manifest-#{@manifest[:recording_id]}", '.json'], nil)
|
||||
File.open(@manifest_file,"w") do |f|
|
||||
f.write(@manifest.to_json)
|
||||
end
|
||||
|
|
@ -113,7 +113,7 @@ module JamRuby
|
|||
|
||||
# make a suitable location to store the output mix, and pass the chosen filepath into the manifest
|
||||
def prepare_output
|
||||
@output_filename = Dir::Tmpname.make_tmpname( ["#{Dir.tmpdir}/audiomixer-output-#{@manifest['recording_id']}", '.ogg'], nil)
|
||||
@output_filename = Dir::Tmpname.make_tmpname( ["#{Dir.tmpdir}/audiomixer-output-#{@manifest[:recording_id]}", '.ogg'], nil)
|
||||
|
||||
# update manifest so that audiomixer writes here
|
||||
@manifest[:output][:filename] = @output_filename
|
||||
|
|
@ -123,7 +123,7 @@ module JamRuby
|
|||
|
||||
# make a suitable location to store an output error file, which will be populated on failure to help diagnose problems.
|
||||
def prepare_error_out
|
||||
@error_out_filename = Dir::Tmpname.make_tmpname( ["#{Dir.tmpdir}/audiomixer-error-out-#{@manifest['recording_id']}", '.ogg'], nil)
|
||||
@error_out_filename = Dir::Tmpname.make_tmpname( ["#{Dir.tmpdir}/audiomixer-error-out-#{@manifest[:recording_id]}", '.ogg'], nil)
|
||||
|
||||
# update manifest so that audiomixer writes here
|
||||
@manifest[:error_out] = @error_out_filename
|
||||
|
|
@ -203,7 +203,13 @@ module JamRuby
|
|||
mix = Mix.find(mix_id)
|
||||
|
||||
begin
|
||||
@manifest = symbolize_keys(JSON.parse(mix.manifest))
|
||||
# bailout check
|
||||
if mix.completed
|
||||
@@log.debug("mix is already completed. bailing")
|
||||
return
|
||||
end
|
||||
|
||||
@manifest = symbolize_keys(mix.manifest)
|
||||
@manifest[:mix_id] = mix_id # slip in the mix_id so that the job can add it to the ogg comments
|
||||
|
||||
# sanity check the manifest
|
||||
|
|
@ -215,25 +221,16 @@ module JamRuby
|
|||
# write the manifest to file, so that it can be passed to audiomixer as an filepath argument
|
||||
prepare
|
||||
|
||||
result = execute(@manifest_file)
|
||||
execute(@manifest_file)
|
||||
|
||||
if result
|
||||
if $? == 0
|
||||
postback
|
||||
post_success(mix)
|
||||
@@log.info("audiomixer job successful. mix_id #{mix_id}")
|
||||
else
|
||||
parse_error_out
|
||||
error_msg = "audiomixer job failed status=#{$?} error_reason=#{error_reason} error_detail=#{error_detail}"
|
||||
@@log.info(error_msg)
|
||||
raise error_msg
|
||||
end
|
||||
if $? == 0
|
||||
postback
|
||||
post_success(mix)
|
||||
@@log.info("audiomixer job successful. mix_id #{mix_id}")
|
||||
else
|
||||
@@log.error("unable to find audiomixer")
|
||||
parse_error_out
|
||||
error_msg = "audiomixer job failed status=#{$?} error_reason=#{error_reason} error_detail=#{error_detail}"
|
||||
@@log.info(error_msg)
|
||||
@error_reason = "unable-find-appmixer"
|
||||
@error_detail = APP_CONFIG.audiomixer_path
|
||||
raise error_msg
|
||||
end
|
||||
rescue Exception => e
|
||||
|
|
@ -250,8 +247,20 @@ module JamRuby
|
|||
private
|
||||
|
||||
def execute(manifest_file)
|
||||
|
||||
unless File.exist? APP_CONFIG.audiomixer_path
|
||||
@@log.error("unable to find audiomixer")
|
||||
error_msg = "audiomixer job failed status=#{$?} error_reason=#{error_reason} error_detail=#{error_detail}"
|
||||
@@log.info(error_msg)
|
||||
@error_reason = "unable-find-appmixer"
|
||||
@error_detail = APP_CONFIG.audiomixer_path
|
||||
raise error_msg
|
||||
end
|
||||
|
||||
|
||||
audiomixer_cmd = "#{APP_CONFIG.audiomixer_path} #{manifest_file}"
|
||||
|
||||
|
||||
@@log.debug("executing #{audiomixer_cmd}")
|
||||
|
||||
system(audiomixer_cmd)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
require 'json'
|
||||
require 'resque'
|
||||
require 'resque-retry'
|
||||
require 'net/http'
|
||||
require 'digest/md5'
|
||||
|
||||
module JamRuby
|
||||
|
||||
# periodically scheduled to find jobs that need retrying
|
||||
class AudioMixerRetry
|
||||
|
||||
@queue = :audiomixer_retry
|
||||
|
||||
@@log = Logging.logger[AudioMixerRetry]
|
||||
|
||||
def self.perform
|
||||
Mix.queue_jobs_needing_retry
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -11,11 +11,9 @@ describe IcecastLimit do
|
|||
it "save" do
|
||||
limit.clients = 9999
|
||||
limit.save
|
||||
puts limit.inspect
|
||||
limit.dumpXml
|
||||
#limit.dumpXml
|
||||
limit.errors.any?.should be_false
|
||||
v = IcecastLimit.find(limit.id)
|
||||
puts v.inspect
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,27 +14,17 @@ describe Mix do
|
|||
@recording.stop
|
||||
@recording.claim(@user, "name", "description", Genre.first, true, true)
|
||||
@recording.errors.any?.should be_false
|
||||
@mix = Mix.schedule(@recording, {})
|
||||
@mix = Mix.schedule(@recording)
|
||||
@mix.reload
|
||||
end
|
||||
|
||||
it "should create a mix for a user's recording properly" do
|
||||
@mix.recording_id.should == @recording.id
|
||||
@mix.manifest.should == {}.to_json
|
||||
@mix.mix_server.should be_nil
|
||||
@mix.started_at.should be_nil
|
||||
@mix.started_at.should_not be_nil
|
||||
@mix.completed_at.should be_nil
|
||||
end
|
||||
|
||||
it "should fail to create a mix if the userid doesn't own the recording" do
|
||||
@user2 = FactoryGirl.create(:user)
|
||||
expect { Mix.schedule(@recording) }.to raise_error
|
||||
end
|
||||
|
||||
it "should fail if the recording doesn't exist" do
|
||||
expect { @mix2 = Mix.schedule(Recording.find('lskdjflsd')) }.to raise_error
|
||||
end
|
||||
|
||||
it "should record when a mix has finished" do
|
||||
Mix.find(@mix.id).finish(10000, "md5hash")
|
||||
@mix.reload
|
||||
|
|
@ -59,7 +49,7 @@ describe Mix do
|
|||
recordings = Recording.list_downloads(@user)["downloads"]
|
||||
recordings.length.should == 1
|
||||
recordings[0][:type].should == "mix"
|
||||
recordings[0][:id].should == @mix.id
|
||||
recordings[0][:id].should == @mix.id.to_s
|
||||
|
||||
recordings = Recording.list_downloads(@user2)["downloads"]
|
||||
recordings.length.should == 0
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ describe RecordedTrack do
|
|||
it "gets a url for the track" do
|
||||
@recorded_track = RecordedTrack.create_from_track(@track, @recording)
|
||||
@recorded_track.save.should be_true
|
||||
@recorded_track.url.should == "recordings/#{@recording.id}/track-#{@track.client_track_id}.ogg"
|
||||
@recorded_track.url.should == "recordings/#{@recorded_track.created_at.strftime('%m-%d-%Y')}/#{@recording.id}/track-#{@track.client_track_id}.ogg"
|
||||
end
|
||||
|
||||
it "signs url" do
|
||||
|
|
|
|||
|
|
@ -175,13 +175,15 @@ describe AudioMixer do
|
|||
AudioMixer.any_instance.stub(:postback) # don't actually post resulting off file up
|
||||
end
|
||||
|
||||
|
||||
describe "perform" do
|
||||
|
||||
# this case does not talk to redis, does not run the real audiomixer, and does not actually talk with s3
|
||||
# but it does talk to the database and verifies all the other logic
|
||||
it "success" do
|
||||
@mix = Mix.schedule(@recording, local_files_manifest)
|
||||
Mix.any_instance.stub(:manifest).and_return(local_files_manifest) # don't actually post resulting off file up
|
||||
@mix = Mix.schedule(@recording)
|
||||
@mix.reload
|
||||
@mix.started_at.should_not be_nil
|
||||
AudioMixer.perform(@mix.id, @mix.sign_url(60 * 60 * 24))
|
||||
@mix.reload
|
||||
@mix.completed.should be_true
|
||||
|
|
@ -191,7 +193,8 @@ describe AudioMixer do
|
|||
|
||||
it "errored" do
|
||||
local_files_manifest[:files][0][:filename] = '/some/path/to/nowhere'
|
||||
@mix = Mix.schedule(@recording, local_files_manifest)
|
||||
Mix.any_instance.stub(:manifest).and_return(local_files_manifest)
|
||||
@mix = Mix.schedule(@recording)
|
||||
expect{ AudioMixer.perform(@mix.id, @mix.sign_url(60 * 60 * 24)) }.to raise_error
|
||||
@mix.reload
|
||||
@mix.completed.should be_false
|
||||
|
|
@ -208,13 +211,15 @@ describe AudioMixer do
|
|||
end
|
||||
|
||||
it "should have been enqueued because mix got scheduled" do
|
||||
@mix = Mix.schedule(@recording, local_files_manifest)
|
||||
Mix.any_instance.stub(:manifest).and_return(local_files_manifest)
|
||||
@mix = Mix.schedule(@recording)
|
||||
AudioMixer.should have_queue_size_of(1)
|
||||
end
|
||||
|
||||
it "should actually run the job" do
|
||||
with_resque do
|
||||
@mix = Mix.schedule(@recording, local_files_manifest)
|
||||
Mix.any_instance.stub(:manifest).and_return(local_files_manifest)
|
||||
@mix = Mix.schedule(@recording)
|
||||
end
|
||||
|
||||
@mix.reload
|
||||
|
|
@ -222,6 +227,23 @@ describe AudioMixer do
|
|||
@mix.length.should == 0
|
||||
@mix.md5.should == 'd41d8cd98f00b204e9800998ecf8427e' # that's the md5 of a touched file, which is what the stubbed :execute does
|
||||
end
|
||||
|
||||
it "bails out with no error if already completed" do
|
||||
with_resque do
|
||||
Mix.any_instance.stub(:manifest).and_return(local_files_manifest)
|
||||
@mix = Mix.schedule(@recording)
|
||||
end
|
||||
|
||||
@mix.reload
|
||||
@mix.completed.should be_true
|
||||
|
||||
with_resque do
|
||||
@mix.enqueue
|
||||
end
|
||||
|
||||
@mix.reload
|
||||
@mix.completed.should be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -258,7 +280,8 @@ describe AudioMixer do
|
|||
|
||||
it "completes" do
|
||||
with_resque do
|
||||
@mix = Mix.schedule(@recording, s3_manifest)
|
||||
Mix.any_instance.stub(:manifest).and_return(s3_manifest)
|
||||
@mix = Mix.schedule(@recording)
|
||||
end
|
||||
|
||||
@mix.reload
|
||||
|
|
@ -270,7 +293,8 @@ describe AudioMixer do
|
|||
it "fails" do
|
||||
with_resque do
|
||||
s3_manifest[:files][0][:filename] = @s3_manager.url('audiomixer/bogus.ogg', :secure => false) # take off some of the trailing chars of the url
|
||||
expect{ Mix.schedule(@recording, s3_manifest) }.to raise_error
|
||||
Mix.any_instance.stub(:manifest).and_return(s3_manifest)
|
||||
expect{ Mix.schedule(@recording) }.to raise_error
|
||||
end
|
||||
|
||||
@mix = Mix.order('id desc').limit(1).first()
|
||||
|
|
|
|||
10
web/Gemfile
10
web/Gemfile
|
|
@ -90,12 +90,12 @@ end
|
|||
|
||||
group :test, :cucumber do
|
||||
gem 'capybara'
|
||||
if ENV['JAMWEB_QT5'] == '1'
|
||||
# necessary on platforms such as arch linux, where pacman -S qt5-webkit is your easiet option
|
||||
gem "capybara-webkit", :git => 'git://github.com/thoughtbot/capybara-webkit.git'
|
||||
else
|
||||
#if ENV['JAMWEB_QT5'] == '1'
|
||||
# # necessary on platforms such as arch linux, where pacman -S qt5-webkit is your easiet option
|
||||
# gem "capybara-webkit", :git => 'git://github.com/thoughtbot/capybara-webkit.git'
|
||||
#else
|
||||
gem "capybara-webkit"
|
||||
end
|
||||
#end
|
||||
gem 'capybara-screenshot'
|
||||
gem 'cucumber-rails', :require => false #, '1.3.0', :require => false
|
||||
gem 'guard-spork', '0.3.2'
|
||||
|
|
|
|||
|
|
@ -10,14 +10,6 @@ class ApiMixesController < ApiController
|
|||
|
||||
respond_to :json
|
||||
|
||||
def schedule
|
||||
begin
|
||||
Mix.schedule(params[:recording_id], current_user, params[:description], params[:manifest])
|
||||
respond_with responder: ApiResponder, :status => 204
|
||||
rescue
|
||||
render :json => { :message => "mix could not be scheduled" }, :status => 403
|
||||
end
|
||||
end
|
||||
|
||||
def next
|
||||
begin
|
||||
|
|
@ -39,7 +31,9 @@ class ApiMixesController < ApiController
|
|||
end
|
||||
|
||||
def download
|
||||
# XXX: needs to permission check
|
||||
@mix = Mix.find(params[:id])
|
||||
raise PermissionError, "You can only download a mix you didn't claim" unless @mix.can_download? current_user
|
||||
|
||||
redirect_to @mix.sign_url
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -234,6 +234,52 @@ class ApiMusicSessionsController < ApiController
|
|||
end
|
||||
end
|
||||
|
||||
def add_comment
|
||||
if params[:id].blank?
|
||||
render :json => { :message => "Session ID is required" }, :status => 400
|
||||
end
|
||||
|
||||
if params[:user_id].blank?
|
||||
render :json => { :message => "User ID is required" }, :status => 400
|
||||
end
|
||||
|
||||
if params[:comment].blank?
|
||||
render :json => { :message => "Comment is required" }, :status => 400
|
||||
end
|
||||
|
||||
comment = MusicSessionComment.new
|
||||
comment.music_session_id = params[:id]
|
||||
comment.creator_id = params[:user_id]
|
||||
comment.comment = params[:comment]
|
||||
comment.save
|
||||
|
||||
if comment.errors.any?
|
||||
render :json => { :message => "Unexpected error occurred" }, :status => 500
|
||||
else
|
||||
render :json => {}, :status => 201
|
||||
end
|
||||
end
|
||||
|
||||
def add_like
|
||||
if params[:id].blank?
|
||||
render :json => { :message => "Session ID is required" }, :status => 400
|
||||
end
|
||||
|
||||
if params[:user_id].blank?
|
||||
render :json => { :message => "User ID is required" }, :status => 400
|
||||
end
|
||||
|
||||
liker = MusicSessionLiker.new
|
||||
liker.music_session_id = params[:id]
|
||||
liker.liker_id = params[:user_id]
|
||||
liker.save
|
||||
|
||||
if liker.errors.any?
|
||||
render :json => { :message => "Unexpected error occurred" }, :status => 500
|
||||
else
|
||||
render :json => {}, :status => 201
|
||||
end
|
||||
end
|
||||
|
||||
def claimed_recording_start
|
||||
@music_session.claimed_recording_start(current_user, ClaimedRecording.find(params[:claimed_recording_id]))
|
||||
|
|
|
|||
|
|
@ -80,6 +80,74 @@ class ApiRecordingsController < ApiController
|
|||
end
|
||||
end
|
||||
|
||||
def add_comment
|
||||
if params[:id].blank?
|
||||
render :json => { :message => "Recording ID is required" }, :status => 400
|
||||
end
|
||||
|
||||
if params[:user_id].blank?
|
||||
render :json => { :message => "User ID is required" }, :status => 400
|
||||
end
|
||||
|
||||
if params[:comment].blank?
|
||||
render :json => { :message => "Comment is required" }, :status => 400
|
||||
end
|
||||
|
||||
comment = RecordingComment.new
|
||||
comment.recording_id = params[:id]
|
||||
comment.creator_id = params[:user_id]
|
||||
comment.comment = params[:comment]
|
||||
comment.save
|
||||
|
||||
if comment.errors.any?
|
||||
render :json => { :message => "Unexpected error occurred" }, :status => 500
|
||||
else
|
||||
render :json => {}, :status => 201
|
||||
end
|
||||
end
|
||||
|
||||
def add_like
|
||||
if params[:id].blank?
|
||||
render :json => { :message => "Recording ID is required" }, :status => 400
|
||||
end
|
||||
|
||||
if params[:user_id].blank?
|
||||
render :json => { :message => "User ID is required" }, :status => 400
|
||||
end
|
||||
|
||||
liker = RecordingLiker.new
|
||||
liker.recording_id = params[:id]
|
||||
liker.liker_id = params[:user_id]
|
||||
liker.save
|
||||
|
||||
if liker.errors.any?
|
||||
render :json => { :message => "Unexpected error occurred" }, :status => 500
|
||||
else
|
||||
render :json => {}, :status => 201
|
||||
end
|
||||
end
|
||||
|
||||
def add_play
|
||||
if params[:id].blank?
|
||||
render :json => { :message => "Recording ID is required" }, :status => 400
|
||||
end
|
||||
|
||||
if params[:user_id].blank?
|
||||
render :json => { :message => "User ID is required" }, :status => 400
|
||||
end
|
||||
|
||||
play = RecordingPlay.new
|
||||
play.recording_id = params[:id]
|
||||
play.player_id = params[:user_id]
|
||||
play.save
|
||||
|
||||
if play.errors.any?
|
||||
render :json => { :message => "Unexpected error occurred" }, :status => 500
|
||||
else
|
||||
render :json => {}, :status => 201
|
||||
end
|
||||
end
|
||||
|
||||
# discard will tell the server the user has no interest in the recording
|
||||
def discard
|
||||
@recording.discard(current_user)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
object @recording
|
||||
|
||||
attributes :id, :band, :created_at, :duration
|
||||
attributes :id, :band, :created_at, :duration, :comment_count, :like_count, :play_count
|
||||
|
||||
child(:recorded_tracks => :recorded_tracks) {
|
||||
attributes :id, :fully_uploaded, :url, :client_track_id, :client_id, :instrument_id
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
rails_env = ENV['RAILS_ENV'] || "production"
|
||||
rails_root = ENV['RAILS_ROOT'] || "/data/github/current"
|
||||
num_workers = rails_env == 'production' ? 5 : 2
|
||||
# this probably needs to be removed from jam-web source, and moved only to chef
|
||||
|
||||
rails_root = ENV['RAILS_ROOT'] || '.'
|
||||
rails_env = ENV['RAILS_ENV'] || "development"
|
||||
num_workers = ENV['NUM_WORKERS'] || 2
|
||||
queues = ENV['QUEUE'] || '*'
|
||||
|
||||
num_workers.times do |num|
|
||||
God.watch do |w|
|
||||
|
|
@ -8,11 +11,11 @@ num_workers.times do |num|
|
|||
w.name = "resque-#{num}"
|
||||
w.group = 'resque'
|
||||
w.interval = 30.seconds
|
||||
w.env = {"QUEUE"=>"critical,high,low", "RAILS_ENV"=>rails_env}
|
||||
w.start = "/usr/bin/rake -f #{rails_root}/Rakefile environment resque:work"
|
||||
w.env = {"QUEUE"=>queues, "RAILS_ENV"=>rails_env}
|
||||
w.start = "/usr/local/bin/bundle exec rake environment resque:work"
|
||||
|
||||
w.uid = 'git'
|
||||
w.gid = 'git'
|
||||
#w.uid = 'jam-resque'
|
||||
#w.gid = 'jam-resque'
|
||||
|
||||
# restart if memory gets too high
|
||||
w.transition(:up, :restart) do |on|
|
||||
|
|
@ -35,7 +35,7 @@ module JamWebEventMachine
|
|||
end
|
||||
end
|
||||
|
||||
if Rails.application.config.websocket_gateway_enable
|
||||
if Rails.application.config.websocket_gateway_enable && !$rails_rake_task
|
||||
|
||||
Thread.new { JamWebsockets::Server.new.run :port => Rails.application.config.websocket_gateway_port,
|
||||
:emwebsocket_debug => Rails.application.config.websocket_gateway_internal_debug,
|
||||
|
|
@ -82,4 +82,4 @@ module JamWebEventMachine
|
|||
end
|
||||
end
|
||||
|
||||
JamWebEventMachine.start unless $rails_rake_task
|
||||
JamWebEventMachine.start
|
||||
|
|
|
|||
|
|
@ -89,7 +89,9 @@ SampleApp::Application.routes.draw do
|
|||
match '/sessions' => 'api_music_sessions#index', :via => :get
|
||||
match '/sessions' => 'api_music_sessions#create', :via => :post
|
||||
match '/sessions/:id/perf' => 'api_music_sessions#perf_upload', :via => :put
|
||||
|
||||
match '/sessions/:id/comments' => 'api_music_sessions#add_comment', :via => :post
|
||||
match '/sessions/:id/likes' => 'api_music_sessions#add_like', :via => :post
|
||||
|
||||
# music session tracks
|
||||
match '/sessions/:id/tracks' => 'api_music_sessions#track_create', :via => :post
|
||||
match '/sessions/:id/tracks' => 'api_music_sessions#track_sync', :via => :put
|
||||
|
|
@ -278,6 +280,9 @@ SampleApp::Application.routes.draw do
|
|||
match '/recordings/:id' => 'api_recordings#show', :via => :get, :as => 'api_recordings_detail'
|
||||
match '/recordings/:id/stop' => 'api_recordings#stop', :via => :post, :as => 'api_recordings_stop'
|
||||
match '/recordings/:id/claim' => 'api_recordings#claim', :via => :post, :as => 'api_recordings_claim'
|
||||
match '/recordings/:id/comments' => 'api_recordings#add_comment', :via => :post, :as => 'api_recordings_add_comment'
|
||||
match '/recordings/:id/likes' => 'api_recordings#add_like', :via => :post, :as => 'api_recordings_add_like'
|
||||
match '/recordings/:id/plays' => 'api_recordings#add_play', :via => :post, :as => 'api_recordings_add_play'
|
||||
match '/recordings/:id/discard' => 'api_recordings#discard', :via => :post, :as => 'api_recordings_discard'
|
||||
match '/recordings/:id/tracks/:track_id/download' => 'api_recordings#download', :via => :get, :as => 'api_recordings_download'
|
||||
match '/recordings/:id/tracks/:track_id/upload_next_part' => 'api_recordings#upload_next_part', :via => :get
|
||||
|
|
@ -291,8 +296,6 @@ SampleApp::Application.routes.draw do
|
|||
match '/claimed_recordings/:id' => 'api_claimed_recordings#update', :via => :put
|
||||
match '/claimed_recordings/:id' => 'api_claimed_recordings#delete', :via => :delete
|
||||
|
||||
# Mixes
|
||||
match '/mixes/schedule' => 'api_mixes#schedule', :via => :post
|
||||
match '/mixes/next' => 'api_mixes#next', :via => :get
|
||||
match '/mixes/:id/finish' => 'api_mixes#finish', :via => :put
|
||||
match '/mixes/:id/download' => 'api_mixes#download', :via => :get
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
# add job scheduler classes here
|
||||
AudioMixerRetry:
|
||||
cron: 0 * * * *
|
||||
class: "JamRuby::AudioMixerRetry"
|
||||
description: "Retries mixes that set the should_retry flag or never started"
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
# Resque tasks
|
||||
require 'resque/tasks'
|
||||
require 'resque_scheduler/tasks'
|
||||
require 'resque'
|
||||
require 'resque_scheduler'
|
||||
|
||||
task :scheduler => :environment do
|
||||
|
||||
# If you want to be able to dynamically change the schedule,
|
||||
# uncomment this line. A dynamic schedule can be updated via the
|
||||
# Resque::Scheduler.set_schedule (and remove_schedule) methods.
|
||||
# When dynamic is set to true, the scheduler process looks for
|
||||
# schedule changes and applies them on the fly.
|
||||
# Note: This feature is only available in >=2.0.0.
|
||||
#Resque::Scheduler.dynamic = true
|
||||
|
||||
# The schedule doesn't need to be stored in a YAML, it just needs to
|
||||
# be a hash. YAML is usually the easiest.
|
||||
Resque.schedule = YAML.load_file(File.join(File.dirname(__FILE__), '../..', 'config/scheduler.yml'))
|
||||
|
||||
# If your schedule already has +queue+ set for each job, you don't
|
||||
# need to require your jobs. This can be an advantage since it's
|
||||
# less code that resque-scheduler needs to know about. But in a small
|
||||
# project, it's usually easier to just include you job classes here.
|
||||
# So, something like this:
|
||||
#require 'jobs'
|
||||
|
||||
Rake::Task['resque:scheduler'].invoke
|
||||
end
|
||||
|
|
@ -2,10 +2,6 @@
|
|||
|
||||
# bundle exec rake audiomixer
|
||||
task :audiomixer do
|
||||
|
||||
|
||||
Rails.application.config.websocket_gateway_enable = false # prevent websocket gateway from starting
|
||||
|
||||
Rake::Task['environment'].invoke
|
||||
|
||||
ENV['QUEUE'] = 'audiomixer'
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
#!/bin/bash -l
|
||||
|
||||
# default config values
|
||||
PORT=3000
|
||||
BUILD_NUMBER=`cat /var/lib/jam-web/BUILD_NUMBER`
|
||||
|
||||
|
||||
CONFIG_FILE="/etc/jam-web/audiomixer-worker-upstart.conf"
|
||||
if [ -e "$CONFIG_FILE" ]; then
|
||||
. "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
# I don't like doing this, but the next command (bundle exec) retouches/generates
|
||||
# the gemfile. This unfortunately means the next debian update doesn't update this file.
|
||||
# Ultimately this means an old Gemfile.lock is left behind for a new package,
|
||||
# and bundle won't run because it thinks it has the wrong versions of gems
|
||||
rm -f Gemfile.lock
|
||||
|
||||
RAILS_ENV=production BUILD_NUMBER=$BUILD_NUMBER QUEUE=audiomixer exec bundle exec rake environment resque:work
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
description "audiomixer-worker"
|
||||
|
||||
start on startup
|
||||
start on runlevel [2345]
|
||||
stop on runlevel [016]
|
||||
|
||||
exec start-stop-daemon --start --chdir /var/lib/jam-web --exec /var/lib/jam-web/script/package/audiomixer-worker-upstart-run.sh
|
||||
|
|
@ -17,42 +17,4 @@ mkdir -p /var/log/$NAME
|
|||
|
||||
chown -R $USER:$GROUP /var/lib/$NAME
|
||||
chown -R $USER:$GROUP /etc/$NAME
|
||||
chown -R $USER:$GROUP /var/log/$NAME
|
||||
|
||||
|
||||
# do the same for audiomixer-worker
|
||||
NAME="audiomxer-worker"
|
||||
|
||||
USER="$NAME"
|
||||
GROUP="$NAME"
|
||||
|
||||
# copy upstart file
|
||||
cp /var/lib/$NAME/script/package/$NAME.conf /etc/init/$NAME.conf
|
||||
|
||||
mkdir -p /var/lib/$NAME/log
|
||||
mkdir -p /var/lib/$NAME/tmp
|
||||
mkdir -p /etc/$NAME
|
||||
mkdir -p /var/log/$NAME
|
||||
|
||||
chown -R $USER:$GROUP /var/lib/$NAME
|
||||
chown -R $USER:$GROUP /etc/$NAME
|
||||
chown -R $USER:$GROUP /var/log/$NAME
|
||||
|
||||
|
||||
# do the same for icecast-worker
|
||||
NAME="icecast-worker"
|
||||
|
||||
USER="$NAME"
|
||||
GROUP="$NAME"
|
||||
|
||||
# copy upstart file
|
||||
cp /var/lib/$NAME/script/package/$NAME.conf /etc/init/$NAME.conf
|
||||
|
||||
mkdir -p /var/lib/$NAME/log
|
||||
mkdir -p /var/lib/$NAME/tmp
|
||||
mkdir -p /etc/$NAME
|
||||
mkdir -p /var/log/$NAME
|
||||
|
||||
chown -R $USER:$GROUP /var/lib/$NAME
|
||||
chown -R $USER:$GROUP /etc/$NAME
|
||||
chown -R $USER:$GROUP /var/log/$NAME
|
||||
chown -R $USER:$GROUP /var/log/$NAME
|
||||
|
|
@ -24,55 +24,4 @@ then
|
|||
fi
|
||||
|
||||
userdel $NAME
|
||||
fi
|
||||
|
||||
|
||||
|
||||
NAME="audiomixer-worker"
|
||||
|
||||
set -e
|
||||
if [ "$1" = "remove" ]
|
||||
then
|
||||
set +e
|
||||
# stop the process, if any is found. we don't want this failing to cause an error, though.
|
||||
sudo stop $NAME
|
||||
set -e
|
||||
|
||||
if [ -f /etc/init/$NAME.conf ]; then
|
||||
rm /etc/init/$NAME.conf
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$1" = "purge" ]
|
||||
then
|
||||
if [ -d /var/lib/$NAME ]; then
|
||||
rm -rf /var/lib/$NAME
|
||||
fi
|
||||
|
||||
userdel $NAME
|
||||
fi
|
||||
|
||||
|
||||
NAME="icecast-worker"
|
||||
|
||||
set -e
|
||||
if [ "$1" = "remove" ]
|
||||
then
|
||||
set +e
|
||||
# stop the process, if any is found. we don't want this failing to cause an error, though.
|
||||
sudo stop $NAME
|
||||
set -e
|
||||
|
||||
if [ -f /etc/init/$NAME.conf ]; then
|
||||
rm /etc/init/$NAME.conf
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$1" = "purge" ]
|
||||
then
|
||||
if [ -d /var/lib/$NAME ]; then
|
||||
rm -rf /var/lib/$NAME
|
||||
fi
|
||||
|
||||
userdel $NAME
|
||||
fi
|
||||
fi
|
||||
|
|
@ -33,81 +33,5 @@ then
|
|||
"$USER" >/dev/null
|
||||
fi
|
||||
|
||||
# NIS no longer a possible problem; stop ignoring errors
|
||||
set -e
|
||||
|
||||
|
||||
|
||||
# do the same for audiomixer-worker
|
||||
NAME="audiomixer-worker"
|
||||
|
||||
set -eu
|
||||
|
||||
HOME="/var/lib/$NAME"
|
||||
USER="$NAME"
|
||||
GROUP="$NAME"
|
||||
|
||||
# if NIS is used, then errors can occur but be non-fatal
|
||||
if which ypwhich >/dev/null 2>&1 && ypwhich >/dev/null 2>&1
|
||||
then
|
||||
set +e
|
||||
fi
|
||||
|
||||
if ! getent group "$GROUP" >/dev/null
|
||||
then
|
||||
addgroup --system "$GROUP" >/dev/null
|
||||
fi
|
||||
|
||||
# creating user if it isn't already there
|
||||
if ! getent passwd "$USER" >/dev/null
|
||||
then
|
||||
adduser \
|
||||
--system \
|
||||
--home $HOME \
|
||||
--shell /bin/false \
|
||||
--disabled-login \
|
||||
--ingroup "$GROUP" \
|
||||
--gecos "$USER" \
|
||||
"$USER" >/dev/null
|
||||
fi
|
||||
|
||||
# NIS no longer a possible problem; stop ignoring errors
|
||||
set -e
|
||||
|
||||
|
||||
|
||||
# do the same for icecast-worker
|
||||
NAME="icecast-worker"
|
||||
|
||||
set -eu
|
||||
|
||||
HOME="/var/lib/$NAME"
|
||||
USER="$NAME"
|
||||
GROUP="$NAME"
|
||||
|
||||
# if NIS is used, then errors can occur but be non-fatal
|
||||
if which ypwhich >/dev/null 2>&1 && ypwhich >/dev/null 2>&1
|
||||
then
|
||||
set +e
|
||||
fi
|
||||
|
||||
if ! getent group "$GROUP" >/dev/null
|
||||
then
|
||||
addgroup --system "$GROUP" >/dev/null
|
||||
fi
|
||||
|
||||
# creating user if it isn't already there
|
||||
if ! getent passwd "$USER" >/dev/null
|
||||
then
|
||||
adduser \
|
||||
--system \
|
||||
--home $HOME \
|
||||
--shell /bin/false \
|
||||
--disabled-login \
|
||||
--ingroup "$GROUP" \
|
||||
--gecos "$USER" \
|
||||
"$USER" >/dev/null
|
||||
fi
|
||||
|
||||
# NIS no longer a possible problem; stop ignoring errors
|
||||
set -e
|
||||
|
|
@ -145,6 +145,7 @@ describe "Session Recordings", :js => true, :type => :feature, :capybara_feature
|
|||
end
|
||||
|
||||
it "claim recording with unique names/descriptions" do
|
||||
pending "intermittent failure on build server, hard to repro on local system"
|
||||
@users.each do |user|
|
||||
name = "#{user.name}'s recording"
|
||||
desc = "#{user.name}'s description"
|
||||
|
|
@ -177,6 +178,7 @@ describe "Session Recordings", :js => true, :type => :feature, :capybara_feature
|
|||
end
|
||||
|
||||
it "a 'Description' is optional" do
|
||||
pending "intermittent failure on build server, hard to repro on local system"
|
||||
@users.each do |user|
|
||||
in_client(user) do
|
||||
claim_recording("my recording", '')
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ gem 'ruby-protocol-buffers', '1.2.2'
|
|||
gem 'em-websocket', '>=0.4.0' #, :path=> "#{workspace}/em-websocket-jam"
|
||||
gem 'amqp'
|
||||
gem 'activerecord', '3.2.13'
|
||||
gem 'actionpack', '3.2.13'
|
||||
gem 'logging'
|
||||
gem 'will_paginate'
|
||||
gem 'actionmailer'
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
module JamWebsockets
|
||||
VERSION = "0.0.1"
|
||||
VERSION = "0.1.1"
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue