Merge branch 'develop' of bitbucket.org:jamkazam/jam-cloud into develop

This commit is contained in:
Jonathan Kolyer 2014-02-20 09:11:44 -06:00
commit b281349bec
74 changed files with 1288 additions and 548 deletions

View File

@ -37,7 +37,6 @@ 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
gem 'jquery-ui-rails'
gem 'rails3-jquery-autocomplete'

View File

@ -26,6 +26,8 @@
= f.input :band, :as => :autocomplete, :url => autocomplete_band_name_admin_bands_path, :input_html => { :id => "jam_ruby_recording_band", :name => "", :id_element => "#jam_ruby_recording_band_id" }
= f.input :band_id, :as => :hidden, :input_html => { :name => "jam_ruby_recording[band_id]" }
= f.input :duration, :hint => 'how long the recording is (in seconds)'
= f.semantic_fields_for :recorded_tracks do |recorded_track, index|
= render 'recorded_track_fields', f: recorded_track
.links

View File

@ -113,4 +113,5 @@ feed_use_recording.sql
feed_autoincrement_primary_key.sql
music_sessions_plays.sql
plays_likes_counters.sql
add_upright_bass.sql
add_upright_bass.sql
music_session_history_public.sql

View File

@ -0,0 +1 @@
ALTER TABLE music_sessions_history ADD COLUMN fan_access BOOLEAN NOT NULL;

View File

@ -57,6 +57,7 @@ require "jam_ruby/models/feedback"
require "jam_ruby/models/feedback_observer"
require "jam_ruby/models/max_mind_geo"
require "jam_ruby/models/max_mind_isp"
require "jam_ruby/models/band_genre"
require "jam_ruby/models/genre"
require "jam_ruby/models/user"
require "jam_ruby/models/user_observer"

View File

@ -1,5 +1,9 @@
module Limits
# session genres
MIN_GENRES_PER_SESSION = 1
MAX_GENRES_PER_SESSION = 3
# band genres
MIN_GENRES_PER_BAND = 1
MAX_GENRES_PER_BAND = 3

View File

@ -20,8 +20,13 @@ module ValidationMessages
SESSION_NOT_FOUND = "Session not found."
# genres
GENRE_LIMIT_EXCEEDED = "No more than 1 genre is allowed."
GENRE_MINIMUM_NOT_MET = "At least 1 genre is required."
RECORDING_GENRE_LIMIT_EXCEEDED = "No more than 1 genre is allowed."
BAND_GENRE_LIMIT_EXCEEDED = "No more than 3 genres are allowed."
SESSION_GENRE_LIMIT_EXCEEDED = "No more than 3 genres are allowed."
RECORDING_GENRE_MINIMUM_NOT_MET = "At least 1 genre is required."
BAND_GENRE_MINIMUM_NOT_MET = "At least 1 genre is required."
SESSION_GENRE_MINIMUM_NOT_MET = "At least 1 genre is required."
# instruments
INSTRUMENT_LIMIT_EXCEEDED = "No more than 5 instruments are allowed."

View File

@ -5,13 +5,20 @@ module JamRuby
:country, :original_fpfile_photo, :cropped_fpfile_photo, :cropped_large_fpfile_photo,
:cropped_s3_path_photo, :cropped_large_s3_path_photo, :crop_selection_photo, :photo_url, :large_photo_url
attr_accessor :updating_photo
attr_accessor :updating_photo, :skip_location_validation
self.primary_key = 'id'
before_save :stringify_photo_info , :if => :updating_photo
validates :biography, no_profanity: true, presence:true
validates :name, presence: true
validates :country, presence: true, :unless => :skip_location_validation
validates :state, presence: true, :unless => :skip_location_validation
validates :city, presence: true, :unless => :skip_location_validation
validate :validate_photo_info
validates :biography, no_profanity: true
validate :require_at_least_one_genre
validate :limit_max_genres
before_save :check_lat_lng
before_save :check_website_url
@ -21,7 +28,8 @@ module JamRuby
has_many :users, :through => :band_musicians, :class_name => "JamRuby::User"
# genres
has_and_belongs_to_many :genres, :class_name => "JamRuby::Genre", :join_table => "bands_genres"
has_many :band_genres, class_name: "JamRuby::BandGenre"
has_many :genres, class_name: "JamRuby::Genre", :through => :band_genres
# recordings
has_many :recordings, :class_name => "JamRuby::Recording", :foreign_key => "band_id"
@ -59,8 +67,7 @@ module JamRuby
end
def recent_history
recordings = ClaimedRecording.joins(:recording)
.where(:recordings => {:band_id => "#{self.id}"})
recordings = Recording.where(:band_id => self.id)
.order('created_at DESC')
.limit(10)
@ -123,74 +130,52 @@ module JamRuby
return recordings
end
def self.build_band(user, params)
id = params[:id]
# ensure person creating this Band is a Musician
unless user.musician?
raise PermissionError, "must be a musician"
end
band = id.blank? ? Band.new : Band.find(id)
# ensure user updating Band details is a Band member
unless band.new_record? || band.users.exists?(user)
raise PermissionError, ValidationMessages::USER_NOT_BAND_MEMBER_VALIDATION_ERROR
end
band.name = params[:name] if params.has_key?(:name)
band.website = params[:website] if params.has_key?(:website)
band.biography = params[:biography] if params.has_key?(:biography)
band.city = params[:city] if params.has_key?(:city)
band.state = params[:state] if params.has_key?(:state)
band.country = params[:country] if params.has_key?(:country)
band.photo_url = params[:photo_url] if params.has_key?(:photo_url)
band.logo_url = params[:logo_url] if params.has_key?(:logo_url)
if params.has_key?(:genres) && params[:genres]
# loop through each genre in the array and save to the db
genres = []
params[:genres].each { |genre_id| genres << Genre.find(genre_id) }
band.genres = genres
end
band
end
# helper method for creating / updating a Band
def self.save(id, name, website, biography, city, state, country, genres, user_id, photo_url, logo_url)
user = User.find(user_id)
def self.save(user, params)
band = build_band(user, params)
# new band
if id.blank?
# ensure person creating this Band is a Musician
unless user.musician?
raise JamRuby::PermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR
end
validate_genres(genres, false)
band = Band.new()
# band update
else
validate_genres(genres, true)
band = Band.find(id)
# ensure user updating Band details is a Band member
unless band.users.exists? user
raise PermissionError, ValidationMessages::USER_NOT_BAND_MEMBER_VALIDATION_ERROR
end
if band.save
# add the creator as the admin
BandMusician.create(:band_id => band.id, :user_id => user.id, :admin => true) if params[:id].blank?
end
# name
band.name = name unless name.nil?
# website
band.website = website unless website.nil?
# biography
band.biography = biography unless biography.nil?
# city
band.city = city unless city.nil?
# state
band.state = state unless state.nil?
# country
band.country = country unless country.nil?
# photo url
band.photo_url = photo_url unless photo_url.nil?
# logo url
band.logo_url = logo_url unless logo_url.nil?
# band.updated_at = Time.now.getutc
band.save!
band.reload
# genres
unless genres.nil?
ActiveRecord::Base.transaction do
# delete all genres for this band first
band.genres.delete_all if id.present?
# loop through each genre in the array and save to the db
genres.each { |genre_id| band.genres << Genre.find(genre_id) }
end
end
# add the creator as the admin
BandMusician.create(:band_id => band.id, :user_id => user_id, :admin => true) if id.blank?
return band
band
end
def escape_filename(path)
@ -274,21 +259,16 @@ module JamRuby
end
private
def self.validate_genres(genres, is_nil_ok)
if is_nil_ok && genres.nil?
return
def require_at_least_one_genre
if self.genres.size < Limits::MIN_GENRES_PER_BAND
errors.add(:genres, ValidationMessages::BAND_GENRE_MINIMUM_NOT_MET)
end
end
if genres.nil?
raise JamRuby::JamArgumentError, ValidationMessages::GENRE_MINIMUM_NOT_MET
else
if genres.size < Limits::MIN_GENRES_PER_BAND
raise JamRuby::JamArgumentError, ValidationMessages::GENRE_MINIMUM_NOT_MET
end
if genres.size > Limits::MAX_GENRES_PER_BAND
raise JamRuby::JamArgumentError, ValidationMessages::GENRE_LIMIT_EXCEEDED
end
def limit_max_genres
if self.genres.size > Limits::MAX_GENRES_PER_BAND
errors.add(:genres, ValidationMessages::BAND_GENRE_LIMIT_EXCEEDED)
end
end

View File

@ -0,0 +1,11 @@
module JamRuby
class BandGenre < ActiveRecord::Base
self.table_name = "bands_genres"
self.primary_key = 'id'
belongs_to :user, class_name: "JamRuby::User"
belongs_to :genre, class_name: "JamRuby::Genre"
end
end

View File

@ -7,10 +7,10 @@ module JamRuby
FIXNUM_MAX = (2**(0.size * 8 -2) -1)
SORT_TYPES = ['date', 'plays', 'likes']
TIME_RANGES = ['today', 'week', 'month', 'all']
TYPE_FILTERS = ['session', 'recording', 'all']
TIME_RANGES = { "today" => 1 , "week" => 7, "month" => 30, "all" => 0}
TYPE_FILTERS = ['music_session_history', 'recording', 'all']
def self.index(params = {})
def self.index(user, params = {})
limit = params[:limit]
limit ||= 20
limit = limit.to_i
@ -20,7 +20,7 @@ module JamRuby
sort ||= 'date'
raise "not valid sort #{sort}" unless SORT_TYPES.include?(sort)
start = params[:start]
start = params[:start].presence
if sort == 'date'
start ||= FIXNUM_MAX
else
@ -30,18 +30,24 @@ module JamRuby
time_range = params[:time_range]
time_range ||= 'month'
raise "not valid time_range #{time_range}" unless TIME_RANGES.include?(time_range)
raise "not valid time_range #{time_range}" unless TIME_RANGES.has_key?(time_range)
type_filter = params[:type]
type_filter ||= 'all'
raise "not valid type #{type_filter}" unless TYPE_FILTERS.include?(type_filter)
query = Feed.includes([:recording]).includes([:music_session_history]).limit(limit)
target_user = params[:user]
target_band = params[:band]
#query = Feed.includes([:recording]).includes([:music_session_history]).limit(limit)
query = Feed.joins("LEFT OUTER JOIN recordings ON recordings.id = feeds.recording_id")
.joins("LEFT OUTER JOIN music_sessions_history ON music_sessions_history.id = feeds.music_session_id")
.limit(limit)
# handle sort
if sort == 'date'
query = query.where("id < #{start}")
query = query.order('id DESC')
query = query.where("feeds.id < #{start}")
query = query.order('feeds.id DESC')
elsif sort == 'plays'
query = query.offset(start)
query = query.order("COALESCE(recordings.play_count, music_sessions_history.play_count) DESC ")
@ -53,14 +59,71 @@ module JamRuby
end
# handle time range
days = TIME_RANGES[time_range]
if days > 0
query = query.where("feeds.created_at > NOW() - '#{days} day'::INTERVAL")
end
# handle type filters
if type_filter == 'session'
query = query.where('music_session_id is not NULL')
if type_filter == 'music_session_history'
query = query.where('feeds.music_session_id is not NULL')
elsif type_filter == 'recording'
query = query.where('recording_id is not NULL')
query = query.where('feeds.recording_id is not NULL')
end
if target_user
if target_user != user.id
require_public_recordings = "claimed_recordings.is_public = TRUE AND"
require_public_sessions = "music_sessions_history.fan_access = TRUE AND"
end
query = query.joins("LEFT OUTER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id AND #{require_public_recordings} (claimed_recordings.user_id = '#{target_user}' OR (recordings.band_id IN (SELECT band_id FROM bands_musicians where user_id='#{target_user}')))")
query = query.joins("LEFT OUTER JOIN music_sessions_user_history ON music_sessions_history.id = music_sessions_user_history.music_session_id AND #{require_public_sessions} music_sessions_user_history.user_id = '#{target_user}'")
query = query.group("feeds.id, feeds.recording_id, feeds.music_session_id, feeds.created_at, feeds.updated_at, recordings.id, music_sessions_history.id")
if sort == 'plays'
query = query.group("COALESCE(recordings.play_count, music_sessions_history.play_count)")
elsif sort == 'likes'
query = query.group("COALESCE(recordings.like_count, music_sessions_history.like_count)")
end
query = query.where('recordings.id is NULL OR claimed_recordings.id IS NOT NULL')
query = query.where('music_sessions_history.id is NULL OR music_sessions_user_history.id IS NOT NULL')
elsif target_band
unless Band.find(target_band).users.include?(user)
require_public_recordings = "claimed_recordings.is_public = TRUE AND"
require_public_sessions = "music_sessions_history.fan_access = TRUE AND"
end
query = query.joins("LEFT OUTER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id AND #{require_public_recordings} recordings.band_id = '#{target_band}'")
query = query.where("music_sessions_history IS NULL OR #{require_public_sessions} music_sessions_history.band_id = '#{target_band}'")
query = query.group("feeds.id, feeds.recording_id, feeds.music_session_id, feeds.created_at, feeds.updated_at, recordings.id, music_sessions_history.id")
if sort == 'plays'
query = query.group("COALESCE(recordings.play_count, music_sessions_history.play_count)")
elsif sort == 'likes'
query = query.group("COALESCE(recordings.like_count, music_sessions_history.like_count)")
end
query = query.where('recordings.id is NULL OR claimed_recordings.id IS NOT NULL')
#query = query.where('music_sessions_history.id is NULL OR music_sessions_user_history.id IS NOT NULL')
else
query = query.joins('LEFT OUTER JOIN claimed_recordings ON recordings.id = claimed_recordings.recording_id AND claimed_recordings.is_public = TRUE')
query = query.joins("LEFT OUTER JOIN music_sessions_user_history ON music_sessions_history.id = music_sessions_user_history.music_session_id AND music_sessions_history.fan_access = TRUE")
query = query.group("feeds.id, feeds.recording_id, feeds.music_session_id, feeds.created_at, feeds.updated_at, recordings.id, music_sessions_history.id")
if sort == 'plays'
query = query.group("COALESCE(recordings.play_count, music_sessions_history.play_count)")
elsif sort == 'likes'
query = query.group("COALESCE(recordings.like_count, music_sessions_history.like_count)")
end
query = query.where('recordings.id is NULL OR claimed_recordings.is_public = TRUE')
query = query.where('music_sessions_history.id is NULL OR music_sessions_user_history.id IS NOT NULL')
end
if query.length == 0
[query, nil]
elsif query.length < limit

View File

@ -4,7 +4,8 @@ module JamRuby
self.primary_key = 'id'
# bands
has_and_belongs_to_many :bands, :class_name => "JamRuby::Band", :join_table => "bands_genres"
has_many :band_genres, class_name: "JamRuby::BandGenre"
has_many :bands, class_name: "JamRuby::Band", :through => :band_genres
# genres
has_and_belongs_to_many :recordings, :class_name => "JamRuby::Recording", :join_table => "recordings_genres"

View File

@ -24,7 +24,7 @@ module JamRuby
has_many :recordings, :class_name => "JamRuby::Recording", :inverse_of => :music_session
belongs_to :band, :inverse_of => :music_sessions, :class_name => "JamRuby::Band", :foreign_key => "band_id"
after_save :require_at_least_one_genre, :limit_max_genres
after_save :require_at_least_one_genre, :limit_max_genres, :sync_music_session_history
after_destroy do |obj|
JamRuby::MusicSessionHistory.removed_music_session(obj.id)
@ -264,18 +264,22 @@ module JamRuby
def require_at_least_one_genre
unless skip_genre_validation
if self.genres.count < Limits::MIN_GENRES_PER_RECORDING
errors.add(:genres, ValidationMessages::GENRE_MINIMUM_NOT_MET)
if self.genres.count < Limits::MIN_GENRES_PER_SESSION
errors.add(:genres, ValidationMessages::SESSION_GENRE_MINIMUM_NOT_MET)
end
end
end
def limit_max_genres
unless skip_genre_validation
if self.genres.count > Limits::MAX_GENRES_PER_RECORDING
errors.add(:genres, ValidationMessages::GENRE_LIMIT_EXCEEDED)
if self.genres.count > Limits::MAX_GENRES_PER_SESSION
errors.add(:genres, ValidationMessages::SESSION_GENRE_LIMIT_EXCEEDED)
end
end
end
def sync_music_session_history
MusicSessionHistory.save(self)
end
end
end

View File

@ -19,7 +19,7 @@ module JamRuby
:class_name => 'JamRuby::MusicSession',
:foreign_key => 'music_session_id')
has_many :music_session_user_histories, :class_name => "JamRuby::MusicSessionUserHistory", :foreign_key => "music_session_id"
has_many :music_session_user_histories, :class_name => "JamRuby::MusicSessionUserHistory", :foreign_key => "music_session_id", :dependent => :delete_all
has_many :comments, :class_name => "JamRuby::MusicSessionComment", :foreign_key => "music_session_id"
has_many :likes, :class_name => "JamRuby::MusicSessionLiker", :foreign_key => "session_id"
has_many :plays, :class_name => "JamRuby::MusicSessionPlay", :foreign_key => "music_session_id"
@ -43,7 +43,6 @@ module JamRuby
self.comments.size
end
def tracks
tracks = []
self.music_session_user_histories.each do |msuh|
@ -128,6 +127,7 @@ module JamRuby
session_history.user_id = music_session.creator.id
session_history.band_id = music_session.band.id unless music_session.band.nil?
session_history.genres = music_session.genres.map { |g| g.id }.join SEPARATOR
session_history.fan_access = music_session.fan_access
session_history.save!
end

View File

@ -3,7 +3,7 @@ module JamRuby
self.primary_key = 'id'
attr_accessible :owner, :owner_id, :band, :band_id, :recorded_tracks_attributes, :mixes_attributes, :claimed_recordings_attributes, :name, :description, :genre, :is_public, :is_downloadable, as: :admin
attr_accessible :owner, :owner_id, :band, :band_id, :recorded_tracks_attributes, :mixes_attributes, :claimed_recordings_attributes, :name, :description, :genre, :is_public, :is_downloadable, :duration, as: :admin
has_many :claimed_recordings, :class_name => "JamRuby::ClaimedRecording", :inverse_of => :recording, :foreign_key => 'recording_id', :dependent => :destroy
has_many :users, :through => :recorded_tracks, :class_name => "JamRuby::User"

View File

@ -275,8 +275,7 @@ module JamRuby
end
def recent_history
recordings = ClaimedRecording.joins(:recording)
.where(:recordings => {:owner_id => "#{self.id}"})
recordings = Recording.where(:owner_id => self.id)
.order('created_at DESC')
.limit(10)

View File

@ -14,12 +14,17 @@ FactoryGirl.define do
musician true
terms_of_service true
#u.association :musician_instrument, factory: :musician_instrument, user: u
before(:create) do |user|
user.musician_instruments << FactoryGirl.build(:musician_instrument, user: user)
end
factory :fan do
musician false
end
factory :admin do
admin true
end
@ -45,7 +50,7 @@ FactoryGirl.define do
factory :music_session do
after(:create) { |session|
MusicSessionHistory.save(session)
FactoryGirl.create(:music_session_user_history, :history => session.music_session_history, :user => session.creator)
}
factory :music_session_with_mount do
@ -61,6 +66,7 @@ FactoryGirl.define do
music_session nil
end
fan_access true
music_session_id { music_session.id }
description { music_session.description }
user_id { music_session.user_id }
@ -101,6 +107,9 @@ FactoryGirl.define do
city "Apex"
state "NC"
country "US"
before(:create) { |band|
band.genres << Genre.first
}
end
factory :genre, :class => JamRuby::Genre do

View File

@ -23,7 +23,7 @@ describe ConnectionManager do
description = "some session"
@conn.exec("INSERT INTO music_sessions (user_id, description, musician_access, approval_required, fan_chat, fan_access) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id", [user_id, description, options[:musician_access], options[:approval_required], options[:fan_chat], options[:fan_access]]) do |result|
session_id = result.getvalue(0, 0)
@conn.exec("INSERT INTO music_sessions_history (music_session_id, description, user_id) VALUES ($1, $2, $3)", [session_id, description, user_id])
@conn.exec("INSERT INTO music_sessions_history (music_session_id, description, user_id, fan_access) VALUES ($1, $2, $3, $4)", [session_id, description, user_id, true])
return session_id
end
end

View File

@ -2,6 +2,11 @@ require 'spec_helper'
describe Band do
before(:all) do
MaxMindIsp.delete_all
MaxMindGeo.delete_all
end
before do
@geocode1 = FactoryGirl.create(:geocoder)
@geocode2 = FactoryGirl.create(:geocoder)
@ -27,7 +32,8 @@ describe Band do
describe "without location data" do
it "should have nil lat/lng values without address" do
@band.update_attributes({ :city => nil,
@band.skip_location_validation = true
@band.update_attributes({ :city => nil,
:state => nil,
:country => nil,
})

View File

@ -3,12 +3,24 @@ require 'spec_helper'
describe User do
let(:user) { FactoryGirl.create(:user) }
let(:band) { FactoryGirl.create(:band, name: "Example Band") }
let(:band_params) {
{
name: "The Band",
biography: "Biography",
city: 'Austin',
state: 'TX',
country: 'US',
genres: ['country']
}
}
before(:each) do
@geocode1 = FactoryGirl.create(:geocoder)
@geocode2 = FactoryGirl.create(:geocoder)
@user = FactoryGirl.create(:user)
@band = Band.save(nil, "Example Band", "www.bands.com", "zomg we rock", "Apex", "NC", "US", ["hip hop"], user.id, nil, nil)
band.touch
end
@ -16,43 +28,43 @@ describe User do
ws = Search.band_search("Example Band").results
ws.length.should == 1
band_result = ws[0]
band_result.name.should == @band.name
band_result.id.should == @band.id
band_result.location.should == @band.location
band_result.name.should == band.name
band_result.id.should == band.id
band_result.location.should == band.location
end
it "should allow search of one band with partial matches" do
ws = Search.band_search("Ex").results
ws.length.should == 1
ws[0].id.should == @band.id
ws[0].id.should == band.id
ws = Search.band_search("Exa").results
ws.length.should == 1
ws[0].id.should == @band.id
ws[0].id.should == band.id
ws = Search.band_search("Exam").results
ws.length.should == 1
ws[0].id.should == @band.id
ws[0].id.should == band.id
ws = Search.band_search("Examp").results
ws.length.should == 1
ws[0].id.should == @band.id
ws[0].id.should == band.id
ws = Search.band_search("Exampl").results
ws.length.should == 1
ws[0].id.should == @band.id
ws[0].id.should == band.id
ws = Search.band_search("Example").results
ws.length.should == 1
ws[0].id.should == @band.id
ws[0].id.should == band.id
ws = Search.band_search("Ba").results
ws.length.should == 1
ws[0].id.should == @band.id
ws[0].id.should == band.id
ws = Search.band_search("Ban").results
ws.length.should == 1
ws[0].id.should == @band.id
ws[0].id.should == band.id
end
it "should not match mid-word searchs" do
@ -67,9 +79,9 @@ describe User do
ws = Search.band_search("Example Band").results
ws.length.should == 1
band_result = ws[0]
band_result.id.should == @band.id
band_result.id.should == band.id
@band.destroy # delete doesn't work; you have to use destroy.
band.destroy # delete doesn't work; you have to use destroy.
ws = Search.band_search("Example Band").results
ws.length.should == 0
@ -79,10 +91,10 @@ describe User do
ws = Search.band_search("Example Band").results
ws.length.should == 1
band_result = ws[0]
band_result.id.should == @band.id
band_result.id.should == band.id
@band.name = "bonus-stuff"
@band.save
band.name = "bonus-stuff"
band.save
ws = Search.band_search("Example Band").results
ws.length.should == 0
@ -90,25 +102,25 @@ describe User do
ws = Search.band_search("Bonus").results
ws.length.should == 1
band_result = ws[0]
band_result.id.should == @band.id
band_result.id.should == band.id
band_result.name.should == "bonus-stuff"
end
it "should tokenize correctly" do
@band2 = Band.save(nil, "Peach pit", "www.bands.com", "zomg we rock", "Apex", "NC", "US", ["hip hop"], user.id, nil, nil)
band2 = FactoryGirl.create(:band, name: 'Peach pit')
ws = Search.band_search("pea").results
ws.length.should == 1
user_result = ws[0]
user_result.id.should == @band2.id
user_result.id.should == band2.id
end
it "should not return anything with a 1 character search" do
@band2 = Band.save(nil, "Peach pit", "www.bands.com", "zomg we rock", "Apex", "NC", "US", ["hip hop"], user.id, nil, nil)
band2 = FactoryGirl.create(:band, name: 'Peach pit')
ws = Search.band_search("pe").results
ws.length.should == 1
user_result = ws[0]
user_result.id.should == @band2.id
user_result.id.should == band2.id
ws = Search.band_search("p").results
ws.length.should == 0

View File

@ -2,7 +2,21 @@ require 'spec_helper'
describe Band do
let(:band) { FactoryGirl.create(:band) }
let(:user) { FactoryGirl.create(:user) }
let(:user2) { FactoryGirl.create(:user) }
let(:fan) { FactoryGirl.create(:fan) }
let(:band) { FactoryGirl.create(:band) }
let(:new_band) { FactoryGirl.build(:band) }
let(:band_params) {
{
name: "The Band",
biography: "Biography",
city: 'Austin',
state: 'TX',
country: 'US',
genres: ['country']
}
}
describe 'website update' do
it 'should have http prefix on website url' do
@ -12,4 +26,65 @@ describe Band do
end
end
describe 'band validations' do
it "minimum genres" do
new_band.save.should be_false
new_band.errors[:genres].should == [ValidationMessages::BAND_GENRE_MINIMUM_NOT_MET]
end
it "maximum genres" do
new_band.genres = Genre.limit(4)
new_band.save.should be_false
new_band.errors[:genres].should == [ValidationMessages::BAND_GENRE_LIMIT_EXCEEDED]
end
end
describe "save" do
it "can succeed" do
band = Band.save(user, band_params)
band.errors.any?.should be_false
band.name.should == band_params[:name]
band.biography.should == band_params[:biography]
band.genres.should == [Genre.find(band_params[:genres][0])]
band.city.should == band_params[:city]
band.state.should == band_params[:state]
band.country.should == band_params[:country]
end
it "ensures user is a musician" do
expect{ Band.save(fan, band_params) }.to raise_error("must be a musician")
end
it "can update" do
band = Band.save(user, band_params)
band.errors.any?.should be_false
band_params[:id] = band.id
band_params[:name] = "changed name"
band = Band.save(user, band_params)
band.errors.any?.should be_false
Band.find(band.id).name.should == band_params[:name]
end
it "stops non-members from updating" do
band = Band.save(user, band_params)
band.errors.any?.should be_false
band_params[:id] = band.id
band_params[:name] = "changed name"
expect{ Band.save(user2, band_params) }.to raise_error(ValidationMessages::USER_NOT_BAND_MEMBER_VALIDATION_ERROR)
end
end
describe "validate" do
it "can pass" do
band = Band.build_band(user, band_params)
band.valid?.should be_true
end
it "can fail" do
band_params[:name] = nil
band = Band.build_band(user, band_params)
band.valid?.should be_false
band.errors[:name].should == ["can't be blank"]
end
end
end

View File

@ -6,16 +6,18 @@ describe Feed do
let (:user2) { FactoryGirl.create(:user) }
let (:user3) { FactoryGirl.create(:user) }
let (:user4) { FactoryGirl.create(:user) }
let (:band) { FactoryGirl.create(:band) }
it "no result" do
feeds, start = Feed.index()
feeds, start = Feed.index(user1)
feeds.length.should == 0
end
it "one claimed recording" do
claimed_recording = FactoryGirl.create(:claimed_recording)
MusicSessionUserHistory.delete_all # the factory makes a music_session while making the recording/claimed_recording
MusicSessionHistory.delete_all # the factory makes a music_session while making the recording/claimed_recording
feeds, start = Feed.index()
feeds, start = Feed.index(user1)
feeds.length.should == 1
feeds[0].recording == claimed_recording.recording
end
@ -25,27 +27,38 @@ describe Feed do
second_track = FactoryGirl.create(:recorded_track, recording: recording)
recording.recorded_tracks << second_track
FactoryGirl.create(:claimed_recording, recording: recording, user: second_track.user)
MusicSessionUserHistory.delete_all # the factory makes a music_session while making the recording/claimed_recording
MusicSessionHistory.delete_all
# verify the mess above only made one recording
Recording.count.should == 1
feeds, start = Feed.index
feeds, start = Feed.index(user1)
feeds.length.should == 1
end
it "one music session" do
music_session = FactoryGirl.create(:music_session)
feeds, start = Feed.index
feeds, start = Feed.index(user1)
feeds.length.should == 1
feeds[0].music_session_history == music_session.music_session_history
end
it "does not return a recording with no claimed recordings" do
recording = FactoryGirl.create(:recording)
MusicSessionUserHistory.delete_all # the factory makes a music_session while making the recording/claimed_recording
MusicSessionHistory.delete_all
feeds, start = Feed.index(user1)
feeds.length.should == 0
end
describe "sorting" do
it "sorts by index (date) DESC" do
claimed_recording = FactoryGirl.create(:claimed_recording)
feeds, start = Feed.index
feeds, start = Feed.index(user1)
feeds.length.should == 2
feeds[0].recording.should == claimed_recording.recording
feeds[1].music_session_history.should == claimed_recording.recording.music_session.music_session_history
@ -57,13 +70,13 @@ describe Feed do
FactoryGirl.create(:recording_play, recording: claimed_recording1.recording, user:claimed_recording1.user)
feeds, start = Feed.index(:sort => 'plays')
feeds, start = Feed.index(user1, :sort => 'plays')
feeds.length.should == 4
FactoryGirl.create(:recording_play, recording: claimed_recording2.recording, user:claimed_recording1.user)
FactoryGirl.create(:recording_play, recording: claimed_recording2.recording, user:claimed_recording2.user)
feeds, start = Feed.index(:sort => 'plays')
feeds, start = Feed.index(user1, :sort => 'plays')
feeds.length.should == 4
feeds[0].recording.should == claimed_recording2.recording
feeds[1].recording.should == claimed_recording1.recording
@ -73,7 +86,7 @@ describe Feed do
FactoryGirl.create(:music_session_play, music_session: claimed_recording1.recording.music_session.music_session_history, user: user3)
feeds, start = Feed.index(:sort => 'plays')
feeds, start = Feed.index(user1, :sort => 'plays')
feeds.length.should == 4
feeds[0].music_session_history.should == claimed_recording1.recording.music_session.music_session_history
feeds[1].recording.should == claimed_recording2.recording
@ -86,13 +99,13 @@ describe Feed do
FactoryGirl.create(:recording_like, recording: claimed_recording1.recording, user:claimed_recording1.user)
feeds, start = Feed.index(:sort => 'likes')
feeds, start = Feed.index(user1, :sort => 'likes')
feeds.length.should == 4
FactoryGirl.create(:recording_like, recording: claimed_recording2.recording, user:claimed_recording1.user)
FactoryGirl.create(:recording_like, recording: claimed_recording2.recording, user:claimed_recording2.user)
feeds, start = Feed.index(:sort => 'likes')
feeds, start = Feed.index(user1, :sort => 'likes')
feeds.length.should == 4
feeds[0].recording.should == claimed_recording2.recording
feeds[1].recording.should == claimed_recording1.recording
@ -101,7 +114,7 @@ describe Feed do
FactoryGirl.create(:music_session_like, music_session_history: claimed_recording1.recording.music_session.music_session_history, user: user2)
FactoryGirl.create(:music_session_like, music_session_history: claimed_recording1.recording.music_session.music_session_history, user: user3)
feeds, start = Feed.index(:sort => 'likes')
feeds, start = Feed.index(user1, :sort => 'likes')
feeds.length.should == 4
feeds[0].music_session_history.should == claimed_recording1.recording.music_session.music_session_history
feeds[1].recording.should == claimed_recording2.recording
@ -114,7 +127,7 @@ describe Feed do
# creates both recording and history record in feed
claimed_recording1 = FactoryGirl.create(:claimed_recording)
feeds, start = Feed.index(:type => 'session')
feeds, start = Feed.index(user1, :type => 'music_session_history')
feeds.length.should == 1
feeds[0].music_session_history == claimed_recording1.recording.music_session.music_session_history
end
@ -123,27 +136,78 @@ describe Feed do
# creates both recording and history record in feed
claimed_recording1 = FactoryGirl.create(:claimed_recording)
feeds, start = Feed.index(:type => 'session')
feeds, start = Feed.index(user1, :type => 'music_session_history')
feeds.length.should == 1
feeds[0].music_session_history == claimed_recording1.recording.music_session.music_session_history
end
end
describe "time ranges" do
it "month" do
# creates both recording and history record in feed
claimed_recording1 = FactoryGirl.create(:claimed_recording)
# move the feed entry created for the recording back more than a months ago
claimed_recording1.recording.feed.created_at = 32.days.ago
claimed_recording1.recording.feed.save!
feeds, start = Feed.index(user1, :type => 'recording')
feeds.length.should == 0
end
it "day" do
# creates both recording and history record in feed
claimed_recording1 = FactoryGirl.create(:claimed_recording)
# move the feed entry created for the recording back more than a months ago
claimed_recording1.recording.feed.created_at = 25.hours.ago
claimed_recording1.recording.feed.save!
feeds, start = Feed.index(user1, :type => 'recording', time_range: 'today')
feeds.length.should == 0
end
it "week" do
# creates both recording and history record in feed
claimed_recording1 = FactoryGirl.create(:claimed_recording)
# move the feed entry created for the recording back more than a months ago
claimed_recording1.recording.feed.created_at = 8.days.ago
claimed_recording1.recording.feed.save!
feeds, start = Feed.index(user1, :type => 'recording', time_range: 'week')
feeds.length.should == 0
end
it "all" do
# creates both recording and history record in feed
claimed_recording1 = FactoryGirl.create(:claimed_recording)
# move the feed entry created for the recording back more than a months ago
claimed_recording1.recording.feed.created_at = 700.days.ago
claimed_recording1.recording.feed.save!
feeds, start = Feed.index(user1, :type => 'recording', time_range: 'all')
feeds.length.should == 1
end
end
describe "pagination" do
it "supports date pagination" do
claimed_recording = FactoryGirl.create(:claimed_recording)
options = {limit: 1}
feeds, start = Feed.index(options)
feeds, start = Feed.index(user1, options)
feeds.length.should == 1
feeds[0].recording.should == claimed_recording.recording
options[:start] = start
feeds, start = Feed.index(options)
feeds, start = Feed.index(user1, options)
feeds.length.should == 1
feeds[0].music_session_history.should == claimed_recording.recording.music_session.music_session_history
options[:start] = start
feeds, start = Feed.index(options)
feeds, start = Feed.index(user1, options)
feeds.length.should == 0
start.should be_nil
end
@ -154,17 +218,17 @@ describe Feed do
FactoryGirl.create(:music_session_like, music_session_history: claimed_recording1.recording.music_session.music_session_history, user: user1)
options = {limit: 1, sort: 'likes'}
feeds, start = Feed.index(options)
feeds, start = Feed.index(user1, options)
feeds.length.should == 1
feeds[0].music_session_history.should == claimed_recording1.recording.music_session.music_session_history
options[:start] = start
feeds, start = Feed.index(options)
feeds, start = Feed.index(user1, options)
feeds.length.should == 1
feeds[0].recording.should == claimed_recording1.recording
options[:start] = start
feeds, start = Feed.index(options)
feeds, start = Feed.index(user1, options)
feeds.length.should == 0
start.should be_nil
end
@ -175,21 +239,221 @@ describe Feed do
FactoryGirl.create(:music_session_play, music_session: claimed_recording1.recording.music_session.music_session_history, user: user1)
options = {limit: 1, sort: 'plays'}
feeds, start = Feed.index(options)
feeds, start = Feed.index(user1, options)
feeds.length.should == 1
feeds[0].music_session_history.should == claimed_recording1.recording.music_session.music_session_history
options[:start] = start
feeds, start = Feed.index(options)
feeds, start = Feed.index(user1, options)
feeds.length.should == 1
feeds[0].recording.should == claimed_recording1.recording
options[:start] = start
feeds, start = Feed.index(options)
feeds, start = Feed.index(user1, options)
feeds.length.should == 0
start.should be_nil
end
end
describe "public feed" do
it "only public" do
claimed_recording1 = FactoryGirl.create(:claimed_recording)
claimed_recording1.is_public = false
claimed_recording1.save!
feeds, start = Feed.index(claimed_recording1.user)
feeds.length.should == 1
claimed_recording1.recording.music_session.fan_access = false
claimed_recording1.recording.music_session.save!
feeds, start = Feed.index(claimed_recording1.user)
feeds.length.should == 0
end
end
describe "band feeds" do
it "does show other band's stuff in this feed" do
other_band = FactoryGirl.create(:band)
music_session = FactoryGirl.create(:music_session, band: other_band)
FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => user1)
claimed_recording1 = FactoryGirl.create(:claimed_recording)
claimed_recording1.is_public = true
claimed_recording1.recording.band = other_band
claimed_recording1.recording.save!
claimed_recording1.save!
feeds, start = Feed.index(user1, band: band.id)
feeds.length.should == 0
end
it "shows public recordings to you and to others" do
user1.bands << band
user1.save!
music_session = FactoryGirl.create(:music_session, band: band)
music_session.music_session_history.fan_access.should be_true
feeds, start = Feed.index(user1, band: band.id)
feeds.length.should == 1
feeds[0].music_session_history.should == music_session.music_session_history
feeds, start = Feed.index(user2, band: band.id)
feeds.length.should == 1
feeds[0].music_session_history.should == music_session.music_session_history
end
it "shows private sessions to you, not to others" do
user1.bands << band
user1.save!
music_session = FactoryGirl.create(:music_session, band: band, fan_access: false)
music_session.music_session_history.fan_access.should be_false
feeds, start = Feed.index(user1, band: band.id)
feeds.length.should == 1
feeds[0].music_session_history.should == music_session.music_session_history
feeds[0].music_session_history.fan_access.should be_false
feeds, start = Feed.index(user2, band: band.id)
feeds.length.should == 0
end
it "shows public recordings to you and to others" do
claimed_recording1 = FactoryGirl.create(:claimed_recording)
claimed_recording1.is_public = true
claimed_recording1.recording.band = band
claimed_recording1.recording.save!
claimed_recording1.save!
feeds, start = Feed.index(claimed_recording1.user, band: band.id)
feeds.length.should == 1
feeds[0].recording.should == claimed_recording1.recording
feeds, start = Feed.index(user1, band: band.id)
feeds.length.should == 1
feeds[0].recording.should == claimed_recording1.recording
end
it "shows private recordings to you, not to others" do
claimed_recording1 = FactoryGirl.create(:claimed_recording)
claimed_recording1.is_public = false
claimed_recording1.recording.band = band
claimed_recording1.recording.save!
claimed_recording1.save!
claimed_recording1.user.bands << band
claimed_recording1.user.save!
feeds, start = Feed.index(claimed_recording1.user, band: band.id)
feeds.length.should == 1
feeds[0].recording.should == claimed_recording1.recording
feeds, start = Feed.index(user1, band: band.id)
feeds.length.should == 0
end
end
describe "user feeds" do
it "does not show stuff from other people" do
music_session = FactoryGirl.create(:music_session)
FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => user2)
claimed_recording1 = FactoryGirl.create(:claimed_recording)
claimed_recording1.is_public = true
claimed_recording1.save!
feeds, start = Feed.index(user1, user: user1.id)
feeds.length.should == 0
end
it "shows public sessions to you and to others" do
music_session = FactoryGirl.create(:music_session)
FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => user1)
feeds, start = Feed.index(user1, user: user1.id)
feeds.length.should == 1
feeds[0].music_session_history.should == music_session.music_session_history
feeds, start = Feed.index(user2, user: user1.id)
feeds.length.should == 1
feeds[0].music_session_history.should == music_session.music_session_history
end
it "shows private sessions to you, not to others" do
music_session = FactoryGirl.create(:music_session, fan_access: false)
music_session.music_session_history.fan_access.should be_false
FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => user1)
feeds, start = Feed.index(user1, user: user1.id)
feeds.length.should == 1
feeds[0].music_session_history.should == music_session.music_session_history
feeds[0].music_session_history.fan_access.should be_false
feeds, start = Feed.index(user2, user: user1.id)
feeds.length.should == 0
end
it "shows public recordings to you and to others" do
claimed_recording1 = FactoryGirl.create(:claimed_recording)
claimed_recording1.is_public = true
claimed_recording1.save!
feeds, start = Feed.index(claimed_recording1.user, user: claimed_recording1.user.id)
feeds.length.should == 1
feeds[0].recording.should == claimed_recording1.recording
feeds, start = Feed.index(user1, user: claimed_recording1.user.id)
feeds.length.should == 1
feeds[0].recording.should == claimed_recording1.recording
end
it "shows private recordings to you, not to others" do
claimed_recording1 = FactoryGirl.create(:claimed_recording)
claimed_recording1.is_public = false
claimed_recording1.save!
feeds, start = Feed.index(claimed_recording1.user, user: claimed_recording1.user.id)
feeds.length.should == 1
feeds[0].recording.should == claimed_recording1.recording
feeds, start = Feed.index(user1, user: claimed_recording1.user.id)
feeds.length.should == 0
end
it "shows band recordings to you even though you did not claim a recording" do
user1.bands << band
user1.save!
user2.bands << band
user2.save!
claimed_recording1 = FactoryGirl.create(:claimed_recording, user: user2)
claimed_recording1.is_public = true
claimed_recording1.recording.band = band
claimed_recording1.recording.save!
claimed_recording1.save!
feeds, start = Feed.index(user1, user: user1.id)
feeds.length.should == 1
feeds[0].recording.should == claimed_recording1 .recording
# make it private; should still be available
claimed_recording1.is_public = false
claimed_recording1.save!
feeds, start = Feed.index(user1, user: user1.id)
feeds.length.should == 1
feeds[0].recording.should == claimed_recording1 .recording
# take user1 out of the band; shouldn't be able to see it
user1.bands.delete_all
feeds, start = Feed.index(user1, user: user1.id)
feeds.length.should == 0
end
end
end

View File

@ -4,18 +4,17 @@ describe MusicSessionHistory do
let(:some_user) { FactoryGirl.create(:user) }
let(:music_session) { FactoryGirl.create(:music_session_no_history) }
let(:history) { FactoryGirl.create(:music_session_history, :music_session => music_session) }
let(:user_history1) { FactoryGirl.create(:music_session_user_history, :history => history, :user => music_session.creator) }
let(:user_history2) { FactoryGirl.create(:music_session_user_history, :history => history, :user => some_user) }
let(:user_history1) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => music_session.creator) }
let(:user_history2) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => some_user) }
it "create" do
history.description.should eql(music_session.description)
music_session.music_session_history.description.should eql(music_session.description)
end
it "unique users" do
user_history1.should_not be_nil
user_history2.should_not be_nil
users = history.unique_users
users = music_session.music_session_history.unique_users
users.length.should eql(2)

View File

@ -4,9 +4,8 @@ describe MusicSessionUserHistory do
let(:some_user) { FactoryGirl.create(:user) }
let(:music_session) { FactoryGirl.create(:music_session_no_history) }
let(:history) { FactoryGirl.create(:music_session_history, :music_session => music_session) }
let(:user_history1) { FactoryGirl.create(:music_session_user_history, :history => history, :user => music_session.creator) }
let(:user_history2) { FactoryGirl.create(:music_session_user_history, :history => history, :user => some_user) }
let(:user_history1) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => music_session.creator) }
let(:user_history2) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => some_user) }
describe "create" do
it {user_history1.music_session_id.should == music_session.id }
@ -78,7 +77,7 @@ describe MusicSessionUserHistory do
end
it "two histories with same user within bounds of history1" do
user_history3 = FactoryGirl.create(:music_session_user_history, :history => history, :user => some_user)
user_history3 = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => some_user)
# if user2 comes and goes 2 times while user one is there, it shouldn't be a false 3
user_history1.session_removed_at = user_history1.created_at + 5
@ -99,7 +98,7 @@ describe MusicSessionUserHistory do
it "two histories with different user within bounds of history1" do
third_user = FactoryGirl.create(:user);
user_history3 = FactoryGirl.create(:music_session_user_history, :history => history, :user => third_user)
user_history3 = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => third_user)
# if user2 comes and goes 2 times while user one is there, it shouldn't be a false 3
user_history1.session_removed_at = user_history1.created_at + 5
@ -120,7 +119,7 @@ describe MusicSessionUserHistory do
it "two overlapping histories with different user within bounds of history1" do
third_user = FactoryGirl.create(:user);
user_history3 = FactoryGirl.create(:music_session_user_history, :history => history, :user => third_user)
user_history3 = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session_history, :user => third_user)
# if user2 comes and goes 2 times while user one is there, it shouldn't be a false 3
user_history1.session_removed_at = user_history1.created_at + 5

View File

@ -61,6 +61,7 @@ Spork.prefork do
#
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |config|
config.color_enabled = true
config.treat_symbols_as_metadata_keys_with_true_values = true
config.run_all_when_everything_filtered = true
config.filter_run :focus

View File

@ -55,7 +55,6 @@ gem 'fog'
gem 'haml-rails'
gem 'unf' #optional fog dependency
gem 'devise', '>= 1.1.2'
#gem 'thin' # the presence of this gem on mac seems to prevent normal startup of rails.
gem 'postgres-copy'
#group :libv8 do
# gem 'libv8', "~> 3.11.8"

Binary file not shown.

After

Width:  |  Height:  |  Size: 758 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -16,9 +16,20 @@
}
function afterShow(data) {
resetForm();
events();
renderActive();
// hide until we know if 'isMember'
$("#btn-follow-band").hide();
$("#btn-edit-band-profile").hide();
resetForm();
events();
determineMembership()
.done(function() {
renderActive();
})
.fail(function(jqXHR) {
app.notifyServerError(jqXHR, "Unable to talk to server")
})
}
function resetForm() {
@ -128,6 +139,16 @@
// refreshes the currently active tab
function renderActive() {
if (isMember) {
$("#btn-follow-band").hide();
$("#btn-edit-band-profile").show();
}
else {
$("#btn-follow-band").show();
$("#btn-edit-band-profile").hide();
}
if ($('#band-profile-about-link').hasClass('active')) {
renderAbout();
}
@ -161,7 +182,6 @@
rest.getBand(bandId)
.done(function(response) {
band = response;
setIsMember();
if (band) {
// name
$('#band-profile-name').html(band.name);
@ -379,47 +399,37 @@
}
}
// TODO: refactor
// checks if person viewing the profile is also a band member
function setIsMember() {
function determineMembership() {
var url = "/api/bands/" + bandId + "/musicians";
$.ajax({
return $.ajax({
type: "GET",
dataType: "json",
url: url,
async: false,
processData:false,
success: function(response) {
$.each(response, function(index, val) {
if (val.id === context.JK.currentUserId) {
isMember = true;
}
});
},
error: app.ajaxError
});
})
.done(function(response) {
isMember = false;
$.each(response, function(index, val) {
if (val.id === context.JK.currentUserId) {
isMember = true;
}
});
})
}
// events for main screen
function events() {
// wire up panel clicks
$('#band-profile-about-link').click(renderAbout);
$('#band-profile-history-link').click(renderHistory);
$('#band-profile-members-link').click(renderMembers);
$('#band-profile-social-link').click(renderSocial);
$('#band-profile-about-link').unbind('click').click(renderAbout);
$('#band-profile-history-link').unbind('click').click(renderHistory);
$('#band-profile-members-link').unbind('click').click(renderMembers);
$('#band-profile-social-link').unbind('click').click(renderSocial);
if (isMember) {
$("#btn-follow-band").hide();
$("#btn-edit-band-profile").show();
}
else {
$("#btn-follow-band").show();
$("#btn-edit-band-profile").hide();
}
$("#btn-edit-band-profile").click(function() {
$('div[layout-id="band/setup"] .hdn-band-id').val(bandId);
context.location = "/client#/band/setup";
$("#btn-edit-band-profile").unbind('click').click(function() {
//$('div[layout-id="band/setup"] .hdn-band-id').val(bandId);
context.location = "/client#/band/setup/" + bandId;
return false;
});
}

View File

@ -21,45 +21,43 @@
var nilOptionText = 'n/a';
var bandId = '';
function is_new_record() {
return bandId.length == 0;
}
function removeErrors() {
$('#band-setup-form .error-text').remove()
$('#band-setup-form .error').removeClass("error")
}
function resetForm() {
removeErrors();
// name
$("#band-name").val('');
var $tdName = $("#tdBandName");
$tdName.find('.error-text').remove();
$tdName.removeClass("error");
// country
$("#band-country").empty();
$("#band-country").val('');
var $tdCountry = $("#tdBandCountry");
$tdCountry.find('.error-text').remove();
$tdCountry.removeClass("error");
// region
$("#band-region").empty();
$("#band-region").val('');
var $tdRegion = $("#tdBandRegion");
$tdRegion.find('.error-text').remove();
$tdRegion.removeClass("error");
// city
$("#band-city").empty();
$("#band-city").val('');
var $tdCity = $("#tdBandCity");
$tdCity.find('.error-text').remove();
$tdCity.removeClass("error");
// description
$("#band-biography").val('');
var $tdBiography = $("#tdBandBiography");
$tdBiography.find('.error-text').remove();
$tdBiography.removeClass("error");
// website
$('#band-website').val('');
resetGenres();
$("#hdn-band-id").val('');
$("#band-setup-step-1").show();
$("#band-setup-step-2").hide();
@ -75,8 +73,6 @@
});
var $tdGenres = $("#tdBandGenres");
$tdGenres.find('.error-text').remove();
$tdGenres.removeClass("error");
}
function getSelectedGenres() {
@ -90,96 +86,32 @@
}
function validateGeneralInfo() {
var isValid = true;
removeErrors();
// name
var $name = $("#band-name");
var $tdName = $("#tdBandName");
var name = $.trim($name.val());
if (name.length === 0) {
$tdName.find('.error-text').remove();
$tdName.addClass("error");
$name.after("<ul class='error-text'><li>Name is required</li></ul>");
isValid = false;
}
else {
$tdName.removeClass("error");
}
var band = buildBand();
// country
var $country = $("#band-country");
var $tdCountry = $("#tdBandCountry");
var country = $.trim($country.val());
if (country.length === 0) {
$tdCountry.find('.error-text').remove();
$tdCountry.addClass("error");
$country.after("<ul class='error-text'><li>Country is required</li></ul>");
isValid = false;
}
else {
$tdCountry.removeClass("error");
}
// region
var $region = $("#band-region");
var $tdRegion = $("#tdBandRegion");
var region = $.trim($region.val());
if (region.length === 0) {
$tdRegion.find('.error-text').remove();
$tdRegion.addClass("error");
$region.after("<ul class='error-text'><li>Region is required</li></ul>");
isValid = false;
}
else {
$tdRegion.removeClass("error");
}
// city
var $city = $("#band-city");
var $tdCity = $("#tdBandCity");
var city = $.trim($city.val());
if (city.length === 0) {
$tdCity.find('.error-text').remove();
$tdCity.addClass("error");
$city.after("<ul class='error-text'><li>City is required</li></ul>");
isValid = false;
}
else {
$tdCity.removeClass("error");
}
// genres (no more than 3)
var $genres = $(".band-setup-genres");
var $tdGenres = $("#tdBandGenres");
var selectedGenres = getSelectedGenres();
if (selectedGenres.length === 0 || selectedGenres.length > 3) {
$tdGenres.find('.error-text').remove();
$tdGenres.addClass("error");
$genres.after("<ul class='error-text'><li>Genre is required (3 maximum)</li></ul>");
isValid = false;
}
else {
$tdGenres.removeClass("error");
}
// description
var $biography = $("#band-biography");
var $tdBiography = $("#tdBandBiography");
var biography = $.trim($biography.val());
if (biography.length === 0) {
$tdBiography.find('.error-text').remove();
$tdBiography.addClass("error");
$biography.after("<ul class='error-text'><li>Biography is required</li></ul>");
isValid = false;
}
else {
$tdBiography.removeClass("error");
}
return isValid;
return rest.validateBand(band);
}
function saveBand() {
function renderErrors(errors) {
var name = context.JK.format_errors("name", errors);
var country = context.JK.format_errors("country", errors);
var state = context.JK.format_errors("state", errors);
var city = context.JK.format_errors("city", errors);
var biography = context.JK.format_errors("biography", errors);
var genres = context.JK.format_errors("genres", errors);
var website = context.JK.format_errors("website", errors);
if(name) $("#band-name").closest('div.field').addClass('error').end().after(name);
if(country) $("#band-country").closest('div.field').addClass('error').end().after(country);
if(state) $("#band-region").closest('div.field').addClass('error').end().after(state);
if(city) $("#band-city").closest('div.field').addClass('error').end().after(city);
if(genres) $(".band-setup-genres").closest('div.field').addClass('error').end().after(genres);
if(biography) $("#band-biography").closest('div.field').addClass('error').end().after(biography);
if(website) $("#band-website").closest('div.field').addClass('error').end().after(website);
}
function buildBand() {
var band = {};
band.name = $("#band-name").val();
band.website = $("#band-website").val();
@ -188,8 +120,13 @@
band.state = $("#band-region").val();
band.country = $("#band-country").val();
band.genres = getSelectedGenres();
return band;
}
if (bandId.length === 0) {
function saveBand() {
var band = buildBand()
if (is_new_record()) {
rest.createBand(band)
.done(function (response) {
createBandInvitations(response.id, function () {
@ -244,8 +181,7 @@
userNames = [];
userIds = [];
userPhotoUrls = [];
//bandId = "1158c8b6-4c92-47dc-82bf-1e390c4f9b2c";
bandId = $("#hdn-band-id").val();
bandId = data.id == 'new' ? '' : data.id;
resetForm();
}
@ -253,10 +189,11 @@
friendSelectorDialog.setCallback(friendSelectorCallback);
loadFriends();
if (bandId.length > 0) {
if (!is_new_record()) {
$("#band-setup-title").html("edit band");
$("#btn-band-setup-save").html("SAVE CHANGES");
$("#band-change-photo").html('Upload band photo.');
$('#tdBandPhoto').css('visibility', 'visible');
// retrieve and initialize band profile data points
loadBandDetails();
@ -276,8 +213,7 @@
$("#band-setup-title").html("set up band");
$("#btn-band-setup-save").html("CREATE BAND");
$("#band-change-photo").html('Upload band photo (optional).');
$('#tdBandPhoto').css('visibility', 'hidden'); // can't upload photo when going through initial setup
}
}
@ -479,8 +415,7 @@
function navigateToBandPhoto(evt) {
evt.stopPropagation();
$("#hdn-band-id").val(bandId);
context.location = '/client#/band/setup/photo';
context.location = '/client#/band/setup/photo/' + bandId;
return false;
}
@ -499,14 +434,24 @@
$('#btn-band-setup-cancel').click(function () {
resetForm();
context.location = "/client#/home";
window.history.go(-1);
return false;
});
$('#btn-band-setup-next').click(function () {
if (validateGeneralInfo()) {
$("#band-setup-step-2").show();
$("#band-setup-step-1").hide();
}
validateGeneralInfo()
.done(function (response) {
$("#band-setup-step-2").show();
$("#band-setup-step-1").hide();
})
.fail(function (jqXHR) {
if(jqXHR.status == 422) {
renderErrors(JSON.parse(jqXHR.responseText))
}
else {
app.notifyServerError(jqXHR, "Unable to validate band")
}
});
});
$('#btn-band-setup-back').click(function () {

View File

@ -18,11 +18,7 @@
var updatingBandPhoto = false;
function beforeShow(data) {
bandId = $("#hdn-band-id").val();
logger.debug("bandId=" + bandId);
if (!bandId) {
context.location = '/client#/home';
}
bandId = data.id;
}
function afterShow(data) {
@ -143,8 +139,7 @@
function navToEditProfile() {
resetForm();
$("#hdn-band-id").val(bandId);
context.location = '/client#/band/setup';
context.location = '/client#/band/setup/' + bandId;
}
function renderBandPhotoSpinner() {

View File

@ -103,6 +103,17 @@
});
}
function validateBand(band) {
return $.ajax({
type: "POST",
dataType: "json",
url: '/api/bands/validate',
contentType: 'application/json',
processData: false,
data: JSON.stringify(band)
});
}
function getBand(bandId) {
return $.ajax({
type: "GET",
@ -894,6 +905,7 @@
this.deleteBandPhoto = deleteBandPhoto;
this.getBandPhotoFilepickerPolicy = getBandPhotoFilepickerPolicy;
this.getBand = getBand;
this.validateBand = validateBand;
this.createBandInvitation = createBandInvitation;
this.updateBandInvitation = updateBandInvitation;
this.removeBandMember = removeBandMember;

View File

@ -678,13 +678,12 @@
$('p', $notify).html( message.text);
}
if (message.icon_url) {
$('#avatar', $notify).attr('src', message.icon_url);
$('#avatar', $notify).show();
$('#notify-avatar', $notify).show();
}
else {
$('#avatar', $notify).hide();
$('#notify-avatar', $notify).hide();
}
if (message.detail) {

View File

@ -512,7 +512,7 @@
bandId: val.id,
biography: val.biography,
band_url: "/client#/bandProfile/" + val.id,
avatar_url: context.JK.resolveBandAvatarUrl(val.logo_url),
avatar_url: context.JK.resolveBandAvatarUrl(val.photo_url),
name: val.name,
location: val.location,
genres: formatGenres(val.genres),
@ -594,7 +594,7 @@
}
function configureBandFollowingButton(following, bandId) {
var $btnFollowBand = $('div[band-id=' + bandId + ']', '#profile-bands').find('#btn-follow-band');
var $btnFollowBand = $('div[band-id=' + bandId + ']', '#profile-bands').find('#btn-follow-band-2');
$btnFollowBand.unbind("click");
if (following) {

View File

@ -86,15 +86,42 @@
8: { "title": "Session Latency", "message": "The latency of your audio device combined with your Internet connection has become high enough to impact your session quality. For troubleshooting tips, click here." }, // NETWORK_PING,
9: {"title": "", "message": ""}, // BITRATE_THROTTLE_WARN,
10: { "title": "Low Bandwidth", "message": "The available bandwidth on your network has become too low,and this may impact your audio quality. For troubleshooting tips, click here." }, // BANDWIDTH_LOW
//IO related events
// IO related events
11: { "title": "Input Rate", "message": "The input rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, click here." }, // INPUT_IO_RATE
12: {"title": "", "message": ""}, // INPUT_IO_JTR,
13: { "title": "Output Rate", "message": "The output rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, click here." }, // OUTPUT_IO_RATE
14: {"title": "", "message": ""}, // OUTPUT_IO_JTR,
// CPU load related
15: { "title": "CPU Utilization High", "message": "The CPU of your computer is unable to keep up with the current processing load, and this may impact your audio quality. For troubleshooting tips, click here." }, // CPU_LOAD
16: {"title": "", "message": ""}, // DECODE_VIOLATIONS,
17: {"title": "", "message": ""} // LAST_THRESHOLD
17: {"title": "", "message": ""}, // LAST_THRESHOLD
18: {"title": "", "message": ""}, // WIFI_NETWORK_ALERT, //user or peer is using wifi
19: {"title": "", "message": ""}, // NO_VALID_AUDIO_CONFIG, // alert the user to popup a config
20: {"title": "", "message": ""}, // AUDIO_DEVICE_NOT_PRESENT, // the audio device is not connected
21: {"title": "", "message": ""}, // RECORD_PLAYBACK_STATE, // record/playback events have occurred
22: {"title": "", "message": ""}, // RUN_UPDATE_CHECK_BACKGROUND, //this is auto check - do
23: {"title": "", "message": ""}, // RUN_UPDATE_CHECK_INTERACTIVE, //this is initiated by user
24: {"title": "", "message": ""}, // STUN_EVENT, // system completed stun test... come get the result
25: {"title": "", "message": ""}, // DEAD_USER_WARN_EVENT, //the backend is not receiving audio from this peer
26: {"title": "", "message": ""}, // DEAD_USER_REMOVE_EVENT, //the backend is removing the user from session as no audio is coming from this peer
27: {"title": "", "message": ""}, // WINDOW_CLOSE_BACKGROUND_MODE, //the user has closed the window and the client is now in background mode
28: {"title": "", "message": ""}, // WINDOW_OPEN_FOREGROUND_MODE, //the user has opened the window and the client is now in forground mode/
29: {"title": "", "message": ""}, // SESSION_LIVEBROADCAST_FAIL, //error of some sort - so can't broadcast
30: {"title": "", "message": ""}, // SESSION_LIVEBROADCAST_ACTIVE, //active
31: {"title": "", "message": ""}, // SESSION_LIVEBROADCAST_STOPPED, //stopped by server/user
32: {"title": "", "message": ""}, // SESSION_LIVEBROADCAST_PINNED, //node pinned by user
33: {"title": "", "message": ""}, // SESSION_LIVEBROADCAST_UNPINNED, //node unpinned by user
34: {"title": "", "message": ""}, // BACKEND_STATUS_MSG, //status/informational message
35: {"title": "", "message": ""}, // LOCAL_NETWORK_VARIANCE_HIGH,//the ping time via a hairpin for the user network is unnaturally high or variable.
//indicates problem with user computer stack or network itself (wifi, antivirus etc)
36: {"title": "", "message": ""}, // LOCAL_NETWORK_LATENCY_HIGH,
37: {"title": "", "message": ""}, // RECORDING_CLOSE, //update and remove tracks from front-end
38: {"title": "", "message": ""} // LAST_ALERT
};
@ -141,7 +168,26 @@
sessionModel.refreshCurrentSession(); // XXX: race condition possible here; other client may not have updated server yet
}, 1000);
}
} else {
}
else if (type === 24) { // STUN_EVENT
var testResults = context.jamClient.NetworkTestResult();
$.each(testResults, function(index, val) {
if (val.bStunFailed) {
// if true we could not reach a stun server
}
else if (val.bRemoteUdpBocked) {
// if true the user cannot communicate with peer via UDP, although they could do LAN based session
}
});
}
else if (type === 25) { // DEAD_USER_WARN_EVENT
}
else if (type === 26) { // DEAD_USER_REMOVE_EVENT
}
else {
context.setTimeout(function() {
var alert = alert_type[type];

View File

@ -116,8 +116,8 @@
latency_text: latencyDescription,
latency_style: latencyStyle,
sortScore: latencyInfo.sortScore,
play_url: "TODO",
join_link_display_style: "block" // showJoinLink ? "block" : "none"
play_url: context.JK.root_url + "sessions/" + session.id,
join_link_display_style: showJoinLink ? "block" : "none"
};
var row = context.JK.fillTemplate(rowTemplate, sessionVals);
@ -131,24 +131,24 @@
return false; // break
}
});
if (!insertedEarly) {
$(tbGroup).append(row);
// wire up the Join Link to the T&Cs dialog
var $parentRow = $('tr[id=' + session.id + ']', tbGroup);
$('.join-link', $parentRow).click(function(evt) {
// If no FTUE, show that first.
if (!(context.jamClient.FTUEGetStatus())) {
app.afterFtue = function() { joinClick(session.id); };
app.layout.showDialog('ftue');
return;
} else {
joinClick(session.id);
}
});
}
// wire up the Join Link to the T&Cs dialog
var $parentRow = $('tr[id=' + session.id + ']', tbGroup);
$('.join-link', $parentRow).click(function(evt) {
// If no FTUE, show that first.
if (!(context.jamClient.FTUEGetStatus())) {
app.afterFtue = function() { joinClick(session.id); };
app.layout.showDialog('ftue');
return;
} else {
joinClick(session.id);
}
});
}
function joinClick(sessionId) {

View File

@ -59,13 +59,13 @@
"mandolin":"mandolin",
"oboe":"oboe",
"other":"other",
"piano":"keyboard",
"piano":"piano",
"saxophone":"saxophone",
"trombone":"trombone",
"trumpet":"trumpet",
"tuba":"tuba",
"ukulele":"ukelele",
"upright bass":"cello",
"upright bass":"upright_bass",
"viola":"viola",
"violin":"violin",
"voice":"voice"

View File

@ -53,12 +53,12 @@
shareDialog.showDialog();
});
$("#txtRecordingComment", $scope).keypress(function(e) {
if (e.which === 13) {
addComment();
$(this).val('');
$(this).blur();
}
$("#btnPostComment").click(function(e) {
if ($.trim($("#txtRecordingComment").val()).length > 0) {
addComment();
$("#txtRecordingComment").val('');
$("#txtRecordingComment").blur();
}
});
}
else {

View File

@ -43,12 +43,12 @@
shareDialog.showDialog();
});
$("#txtSessionComment").keypress(function(e) {
if (e.which === 13) {
addComment();
$(this).val('');
$(this).blur();
}
$("#btnPostComment").click(function(e) {
if ($.trim($("#txtSessionComment").val()).length > 0) {
addComment();
$("#txtSessionComment").val('');
$("#txtSessionComment").blur();
}
});
}
else {

View File

@ -62,7 +62,11 @@
}
function beforeShow() {
reset();
reset();
}
function afterShow() {
$(dialogId + ' input[name=email]').focus();
}
function afterHide() {
@ -73,6 +77,7 @@
var dialogBindings = {
'beforeShow' : beforeShow,
'afterShow' : afterShow,
'afterHide': afterHide
};

View File

@ -1,5 +1,6 @@
@import "client/common.css.scss";
.band-setup-bio {
height:90px;
overflow:auto;
@ -21,7 +22,7 @@
.avatar-space {
color: $color2;
margin-bottom: 20px;
margin: 20px;
position:relative;
min-height:300px;
@ -336,4 +337,12 @@
.easydropdown-wrapper {
width:80%;
}
div.field {
margin: 10px;
}
label {
margin-bottom:2px;
}
}

View File

@ -159,6 +159,19 @@ body.web {
font-weight:bold;
color:#ED3618;
}
.button-orange {
margin: 0px 8px 0px 8px;
background-color: #ED3618;
border: solid 1px #F27861;
outline: solid 2px #ED3618;
padding: 3px 10px;
font-size: 12px;
font-weight: 300;
cursor: pointer;
color: #FC9;
text-decoration: none;
}
}
.landing-comment-scroller {

View File

@ -45,7 +45,6 @@
.recording-slider {
position:absolute;
left:25%;
top:0px;
}

View File

@ -14,38 +14,26 @@ class ApiBandsController < ApiController
def show
@band = Band.find(params[:id])
respond_with_model(@band)
end
def create
@band = Band.save(nil,
params[:name],
params[:website],
params[:biography],
params[:city],
params[:state],
params[:country],
params[:genres],
current_user.id,
params[:photo_url],
params[:logo_url])
respond_with @band, responder: ApiResponder, :status => 201, :location => api_band_detail_url(@band)
@band = Band.save(current_user, params)
respond_with_model(@band, new: true, location: lambda { return api_band_detail_url(@band.id) })
end
def update
@band = Band.save(params[:id],
params[:name],
params[:website],
params[:biography],
params[:city],
params[:state],
params[:country],
params[:genres],
current_user.id,
params[:photo_url],
params[:logo_url])
@band = Band.save(current_user, params)
respond_with @band, responder: ApiResponder, :status => :ok
respond_with_model(@band)
end
def validate
@band = Band.build_band(current_user, params)
@band.valid?
respond_with_model(@band)
end
def musician_index

View File

@ -28,7 +28,26 @@ class ApiController < ApplicationController
end
end
protected
def respond_with_model(model, options = {})
if model.errors.any?
response.status = :unprocessable_entity
respond_with model
else
status = options[:new] && options[:new] == true ? 201 : 200
redirect_on_success = options[:location]
if redirect_on_success
location = redirect_on_success.call
raise "location must return something" unless location # development time error
respond_with model, responder: ApiResponder, status: status, location: location
else
respond_with model, responder: ApiResponder, status: status
end
end
end
def auth_user
unless current_user.id == params[:id]
raise PermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR

View File

@ -3,11 +3,14 @@ class ApiFeedsController < ApiController
respond_to :json
def index
@feeds, @next = Feed.index(user: current_user,
@feeds, @next = Feed.index(current_user,
start: params[:since],
limit: params[:limit],
sort: params[:sort],
time_range: params[:time_range])
time_range: params[:time_range],
type: params[:type],
user: params[:user],
band: params[:band])
render "api_feeds/index", :layout => nil
end

View File

@ -0,0 +1,2 @@
object @band

View File

@ -7,7 +7,7 @@ glue :music_session_history do
'music_session_history'
end
attributes :id, :description, :genres, :created_at, :session_removed_at, :comment_count, :like_count, :play_count
attributes :id, :description, :genres, :created_at, :session_removed_at, :comment_count, :like_count, :play_count, :fan_access
child(:user => :creator) {
@ -67,7 +67,7 @@ glue :recording do
child(:claimed_recordings => :claimed_recordings) {
attributes :id, :name, :description, :is_public, :is_downloadable, :genre_id
attributes :id, :name, :description, :is_public, :genre_id
child(:user => :creator) {
attributes :id, :first_name, :last_name, :photo_url

View File

@ -1,5 +1,5 @@
<!-- Profile -->
<div layout="screen" layout-id="band/setup" class="screen secondary" id="band-setup">
<div layout="screen" layout-id="band/setup" layout-arg="id" class="screen secondary" id="band-setup">
<div class="content-head">
<div class="content-icon">
<%= image_tag "content/icon_bands.png", :size => "19x19" %>
@ -13,7 +13,6 @@
<div class="content-body-scroller">
<form id="band-setup-form">
<div style="display:block;">
<input id="hdn-band-id" class="hdn-band-id" type="hidden" value="" />
<div id="band-setup-step-1" class="content-wrapper" style="padding:10px 35px 10px 35px;">
<br />
<table width="100%" cellpadding="0" cellspacing="0">
@ -21,44 +20,66 @@
<td valign="top" colspan="2">
<h2>Step 1: General Information</h2>
</td>
<td valign="middle" rowspan="2" width="33%">
<td id="tdBandPhoto" valign="middle" rowspan="2" width="33%">
<a href="#" class="avatar-profile">
<%= image_tag "shared/avatar_generic_band.png", {:id => "band-avatar", :align=>"absmiddle", :height => 88, :width => 88 } %>
</a>
<br/><br/>
<a id="band-change-photo" href="#" class="small ml20">Upload band photo.</a><br clear="all"><br/>
</td>
</tr>
<tr>
<td id="tdBandName" valign="middle" width="33%">Band Name:<br />
<td id="tdBandName" valign="middle" width="33%">
<div class="field">
<label for="band-name">Band Name:</label>
<input id="band-name" type="text" maxlength="1024" value="" class="w80"><br />
</div>
</td>
<td valign="middle" width="33%">Web Site:<br />
<td id="tdBandWebsite" valign="middle" width="33%">
<div class="field">
<label for="band-website">Web Site:</label>
<input id="band-website" type="text" maxlength="4000" value="" class="w80">
</div>
</td>
</tr>
<tr>
<td id="tdBandCountry" valign="middle">Country:<br />
<td id="tdBandCountry" valign="middle">
<div class="field">
<label for="band-country">Country:</label>
<select id="band-country" class="w80">
</select><br /><br />
</select>
</div>
</td>
<td id="tdBandRegion" valign="middle">State/Region:<br />
<select id="band-region" class="w80">
</select><br /><br />
<td id="tdBandRegion" valign="middle">
<div class="field">
<label for="band-region">State/Region:</label>
<select id="band-region" class="w80">
</select>
</div>
</td>
<td id="tdBandCity" valign="middle">City:<br />
<td id="tdBandCity" valign="middle">
<div class="field">
<label for="band-city">City:</label>
<select id="band-city" class="w80">
</select><br /><br />
</select>
</div>
</td>
</tr>
<tr>
<td id="tdBandGenres" valign="top">Genres:<br />
<td id="tdBandGenres" valign="top">
<div class="field">
<label for="band-genres">Genres:</label>
<div class="band-setup-genres w90">
<table id="band-genres" width="100%" cellpadding="10" cellspacing="6"></table>
</div>
</div>
</td>
<td id="tdBandBiography" valign="top" colspan="2">Description / Bio:<br />
<td id="tdBandBiography" valign="top" colspan="2">
<div class="field">
<label for="band-biography">Description / Bio:</label>
<textarea id="band-biography" class="band-setup-bio w90" maxlength="4000"></textarea>
</div>
</td>
</tr>
</table>

View File

@ -1,5 +1,5 @@
<!-- Band Photo Setup -->
<div layout="screen" layout-id="band/setup/photo" class="screen secondary">
<div layout="screen" layout-id="band/setup/photo" layout-arg="id" class="screen secondary">
<!-- header -->
<div class="content-head">
<!-- icon -->
@ -12,9 +12,12 @@
</div>
<!-- end header -->
<!-- profile scrolling area -->
<div id="band-setup-photo-content-scroller" class="content-scroller">
<div class="content-body">
<!-- profile scrolling area -->
<div id="band-setup-photo-content-scroller" class="content-scroller">
</div>
</div>
<!-- end content scrolling area -->
</div>

View File

@ -71,7 +71,7 @@
<div class="{latency_style}" style="margin:auto">{latency_text}</div>
</td>
<td style="text-align:center; vertical-align:middle;">
<a id="play-link" href="{play_url}">
<a id="play-link" rel="external" href="{play_url}">
<%= image_tag "content/icon_playbutton.png", :size => "20x20" %>
</a>
</td>

View File

@ -1,7 +1,7 @@
<div layout="notify" id="notification" class="hidden">
<h2>Notification</h2>
<!-- avatar -->
<a href="#" class="avatar_large mr20">
<a href="#" id="notify-avatar" class="avatar_large mr20">
<img id="avatar" />
</a>
<p></p>

View File

@ -127,13 +127,13 @@
<script type="text/template" id="template-no-bands">
<div class="when-empty">
Not In Any Bands:<br/>
<a id="band-setup-link" href="/client#/band/setup">Set Up Your Band</a>
<a id="band-setup-link" href="/client#/band/setup/new">Set Up Your Band</a>
</div>
</script>
<script type="text/template" id="template-more-bands">
<div class="when-empty">
<a id="band-setup-link" href="/client#/band/setup">Set Up Another Band</a>
<a id="band-setup-link" href="/client#/band/setup/new">Set Up Another Band</a>
</div>
</script>
@ -176,7 +176,7 @@
</div>
<div class="result-list-button-wrapper">
<a class="button-orange smallbutton" href="{band_url}">PROFILE</a>
<a id="btn-follow-band" class="button-orange smallbutton">FOLLOW</a>
<a id="btn-follow-band-2" class="button-orange smallbutton">FOLLOW</a>
</div>
</div>
</div>

View File

@ -52,10 +52,13 @@
<br clear="all" />
<div class="w100">
<div class="recording-controls">
<a class="left mr20" href="#"><%= image_tag "content/icon_playbutton.png", {:width => 20, :height => 20, :alt => ""} %></a>
<a class="left mr20" href="#"><%= image_tag "content/icon_playbutton.png", {:id => "imgPlayPause", :width => 20, :height => 20, :alt => ""} %></a>
<% if @music_session.session_removed_at.blank? %>
<div class="session-status">SESSION IN PROGRESS</div>
<div class="recording-current">1:23</div>
<div class="recording-current"></div>
<audio controls preload="none" style="display:none;">
<source src="<%= @music_session.music_session.mount.url %>" type="<%= @music_session.music_session.mount.resolve_string(:mime_type) %>">
</audio>
<% else %>
<div class="session-status-ended">LIVE SESSION ENDED</div>
<% end %>
@ -99,8 +102,38 @@
<% content_for :extra_js do %>
<script type="text/javascript">
$(function () {
var showMusicSession = new JK.ShowMusicSession(JK.app);
showMusicSession.initialize("<%= @music_session.id %>");
var showMusicSession = new JK.ShowMusicSession(JK.app);
showMusicSession.initialize("<%= @music_session.id %>");
// remainder of this code is related to playing/pausing the recording
var htmlAudio = $(".recording-controls").find('audio').get(0);
function formatTime(time) {
var minutes = Math.floor(time / 60);
var seconds = Math.floor(time % 60);
return minutes.toString() + ":" + (seconds > 9 ? seconds.toString() : '0' + seconds.toString());
}
$(htmlAudio).on('timeupdate', function() {
$(".recording-current").html(formatTime(htmlAudio.currentTime));
// reset icon to play and slider to far left when done
if (percentComplete === 100) {
$("#imgPlayPause").attr('src', '/assets/content/icon_playbutton.png');
}
});
$("#btnPlayPause").click(function() {
if (htmlAudio.paused) {
htmlAudio.play();
$("#imgPlayPause").attr('src', '/assets/content/icon_pausebutton.png');
}
else {
htmlAudio.pause();
$("#imgPlayPause").attr('src', '/assets/content/icon_playbutton.png');
}
});
});
})
</script>
<% end %>

View File

@ -18,7 +18,7 @@
<% end %>
<div class="landing-band">
<% unless @claimed_recording.recording.band.nil? %>
<% unless @claimed_recording.recording.band.blank? %>
<div class="landing-avatar">
<% unless @claimed_recording.recording.band.photo_url.blank? %>
<%= image_tag "#{@claimed_recording.recording.band.photo_url}", {:alt => ""} %>
@ -51,17 +51,20 @@
<br clear="all" /><%= @claimed_recording.description %><br /><br />
<div class="w100">
<div class="recording-controls">
<a id="btnPlay" class="left"><%= image_tag "content/icon_playbutton.png", {:width => 20, :height => 20, :alt => ""} %></a>
<a id="btnPlayPause" class="left" href="#"><%= image_tag "content/icon_playbutton.png", {:id => "imgPlayPause", :width => 20, :height => 20, :alt => ""} %></a>
<div class="recording-position">
<div class="recording-time">0:00</div>
<div class="recording-playback">
<div class="recording-slider"><%= image_tag "content/slider_playcontrols.png", {:width => 5, :height => 16, :alt => ""} %></div>
</div>
<div class="recording-time">4:59</div>
<div id="recordingDuration" class="recording-time"></div>
</div>
<div class="recording-current">1:23</div>
<div class="recording-current">0:00</div>
<audio controls preload="none" style="display:none;">
<source src="<%= @claimed_recording.mix.mp3_url %>">
<source src="<%= @claimed_recording.mix.ogg_url %>">
</audio>
</div>
<div class="left white"><%= @claimed_recording.genre_id.capitalize %></div>
<div class="right white">
<span id="spnPlayCount"><%= @claimed_recording.recording.play_count %></span>
@ -101,7 +104,45 @@
$(function () {
var showRecording = new JK.ShowRecording(JK.app);
showRecording.initialize("<%= @claimed_recording.id %>", "<%= @claimed_recording.recording_id %>");
})
// remainder of this code is related to playing/pausing the recording
var htmlAudio = $(".recording-controls").find('audio').get(0);
var durationInitialized = false;
function formatTime(time) {
var minutes = Math.floor(time / 60);
var seconds = Math.floor(time % 60);
return minutes.toString() + ":" + (seconds > 9 ? seconds.toString() : '0' + seconds.toString());
}
// this calculates the original
$(htmlAudio).on('timeupdate', function() {
if (!durationInitialized) {
$("#recordingDuration").html(formatTime(htmlAudio.duration));
durationInitialized = true;
}
var percentComplete = (htmlAudio.currentTime / htmlAudio.duration) * 100;
$(".recording-slider").css({'left': percentComplete + '%'});
$(".recording-current").html(formatTime(htmlAudio.currentTime));
// reset icon to play and slider to far left when done
if (percentComplete === 100) {
$("#imgPlayPause").attr('src', '/assets/content/icon_playbutton.png');
$(".recording-slider").css({'left': 0 + '%'});
}
});
$("#btnPlayPause").click(function() {
if (htmlAudio.paused) {
htmlAudio.play();
$("#imgPlayPause").attr('src', '/assets/content/icon_pausebutton.png');
}
else {
htmlAudio.pause();
$("#imgPlayPause").attr('src', '/assets/content/icon_playbutton.png');
}
});
});
</script>
<% end %>

View File

@ -6,6 +6,9 @@
<div class="left w80 p10">
<textarea id="<%= id %>" class="w100 p5 f15" rows="2" placeholder="Enter a comment..."></textarea>
</div>
<div class="right mr20">
<a href="#" id="btnPostComment" class="button-orange">POST</a>
</div>
<br clear="all" />
<div class="landing-comment-scroller">

View File

@ -4,14 +4,15 @@
<% recent_history.each do |history_record| %>
<% if history_record.instance_of? ClaimedRecording %>
<% if history_record.instance_of? Recording %>
<div class="grey f16">
<em><%= history_record.created_at.strftime("%b #{history_record.created_at.day.ordinalize}") %>:</em>
</div>
<div class="f16">
<span class="orange"><strong>RECORDING:</strong></span>
<a recording-id="<%= history_record.recording_id %>" hoveraction="recording" href="/recordings/<%= history_record.recording_id %>" class="white">Test</a>
<a recording-id="<%= history_record.claimed_recordings.first.id %>" hoveraction="recording" href="/recordings/<%= history_record.claimed_recordings.first.id %>" class="white"><%= history_record.claimed_recordings.first.name %></a>
</div>
<div class="f13 lightgrey"><%= history_record.claimed_recordings.first.description %></div>
<% elsif history_record.instance_of? MusicSessionHistory %>
<div class="grey f16">
@ -31,9 +32,9 @@
<span class="grey">Session Ended. Unavailable.</span>
<% end %>
</div>
<div class="f13 lightgrey"><%= history_record.description %></div>
<% end %>
<div class="f13 lightgrey"><%= history_record.description %></div>
<% if history_record != recent_history.last %>
<br /><br />
<% end %>

View File

@ -21,7 +21,7 @@
<!-- <li class="payments"><%= link_to "Payments", '/client#/account/payments' %></li> -->
<% if current_user && current_user.musician? %>
<li class="audio"><%= link_to "Audio Gear", '/client#/account/audio' %></li>
<li class="band-setup"><%= link_to "Band Setup", '/client#/band/setup' %></li>
<li class="band-setup"><%= link_to "Band Setup", '/client#/band/setup/new' %></li>
<% end %>
<li class="invite-friends"><span class='menuheader'><span class="arrow-right"></span><%= link_to "Invite Friends", '#' %></span>
<ul class="shortcuts-submenu">

View File

@ -225,6 +225,7 @@ SampleApp::Application.routes.draw do
# bands
match '/bands' => 'api_bands#index', :via => :get
match '/bands/validate' => 'api_bands#validate', :via => :post
match '/bands/:id' => 'api_bands#show', :via => :get, :as => 'api_band_detail'
match '/bands' => 'api_bands#create', :via => :post
match '/bands/:id' => 'api_bands#update', :via => :post

View File

@ -43,9 +43,6 @@ MusicSessionManager < BaseManager
# save session parameters for next session
User.save_session_settings(user, music_session)
# save session history
MusicSessionHistory.save(music_session)
# auto-join this user into the newly created session
as_musician = true
connection = ConnectionManager.new.join_music_session(user, client_id, music_session, as_musician, tracks)
@ -96,12 +93,9 @@ MusicSessionManager < BaseManager
update[:genres] = genre_array
end
if music_session.update_attributes(update)
# save session history (only thing that could change is description)
MusicSessionHistory.save(music_session)
end
music_session.update_attributes(update)
return music_session
music_session
end
def participant_create(user, music_session_id, client_id, as_musician, tracks)

View File

@ -1,16 +1,16 @@
namespace :db do
desc "Import a maxmind database; run like this: rake db:import_maxmind_geo file=<path_to_Geo139.csv>"
task :import_maxmind_geo do
task import_maxmind_geo: :environment do
MaxMindGeo.import_from_max_mind ENV['file']
end
desc "Import a maxmind isp database; run like this: rake db:import_maxmind_isp file=<path_to_Geo142.csv>"
task :import_maxmind_isp do
task import_maxmind_isp: :environment do
MaxMindIsp.import_from_max_mind ENV['file']
end
desc "Create a fake set of maxmind data"
task :phony_maxmind do
task phony_maxmind: :environment do
MaxMindManager.active_record_transaction do |manager|
manager.create_phony_database()
end

View File

@ -31,6 +31,13 @@ namespace :db do
DatabaseCleaner.clean
end
task populate: :environment do
make_friends
make_bands
make_band_members
make_recording
end
task populate_friends: :environment do
make_friends
end
@ -48,44 +55,7 @@ namespace :db do
end
task populate_claimed_recording: :environment do
# need 4 users.
users = User.where(musician: true).limit(4)
raise "need at least 4 musicians in the database to create a recording" if users.length < 4
user1 = users[0]
user2 = users[1]
user3 = users[2]
user4 = users[3]
recording = Recording.new
recording.name = 'sample data'
recording.owner = user1
make_recorded_track(recording, user1, 'bass guitar', 'f86949abc213a3ccdc9d266a2ee56453', 2579467, 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/track-adrian-bass.ogg')
make_recorded_track(recording, user1, 'voice', '264cf4e0bf14d44109322a504d2e6d18', 2373055, 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/track-adrian-vox.ogg')
make_recorded_track(recording, user2, 'electric guitar', '9f322e1991b8c04b00dc9055d6be933c', 2297867, 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/track-chris-guitar.ogg')
make_recorded_track(recording, user2, 'voice', '3c7dcb7c4c35c0bb313fc15ee3e6bfd5', 2244968, 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/track-chris-vox.ogg')
make_recorded_track(recording, user3, 'voice', '10ca4c6ef5b98b3489ae8da1c7fa9cfb', 2254275, 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/track-matt-lead-vox.ogg')
make_recorded_track(recording, user4, 'drums', 'ea366f482fa969e1fd8530c13cb75716', 2386250, 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/track-randy-drum1.ogg')
make_recorded_track(recording, user4, 'drums', '4c693c6e99117719c6340eb68b0fe574', 2566463, 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/track-randy-drum2.ogg')
make_claimed_recording(recording, user1, 'Poison', 'Classic song that you all know -- user1')
make_claimed_recording(recording, user2, 'Poison', 'Classic song that you all know -- user2')
make_claimed_recording(recording, user3, 'Poison', 'Classic song that you all know -- user3')
make_claimed_recording(recording, user4, 'Poison', 'Classic song that you all know -- user4')
mix = Mix.new
mix.started_at = Time.now
mix.completed_at = Time.now
mix[:ogg_url] = 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/master-out.ogg'
mix.ogg_md5 = 'f1fee708264602e1705638e53f0ea667'
mix.ogg_length = 2500633
mix[:mp3_url] = 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/master-out.mp3'
mix.mp3_md5 = 'df05abad96e5cb8439f7cd6e31b5c503'
mix.mp3_length = 3666137
mix.completed = true
recording.mixes << mix
recording.save!(validate:false)
make_recording
end
desc "Fill database with music session sample data"
@ -257,3 +227,44 @@ def make_claimed_recording(recording, user, name, description)
end
def make_recording
# need 4 users.
users = User.where(musician: true).limit(4)
raise "need at least 4 musicians in the database to create a recording" if users.length < 4
user1 = users[0]
user2 = users[1]
user3 = users[2]
user4 = users[3]
recording = Recording.new
recording.name = 'sample data'
recording.owner = user1
make_recorded_track(recording, user1, 'bass guitar', 'f86949abc213a3ccdc9d266a2ee56453', 2579467, 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/track-adrian-bass.ogg')
make_recorded_track(recording, user1, 'voice', '264cf4e0bf14d44109322a504d2e6d18', 2373055, 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/track-adrian-vox.ogg')
make_recorded_track(recording, user2, 'electric guitar', '9f322e1991b8c04b00dc9055d6be933c', 2297867, 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/track-chris-guitar.ogg')
make_recorded_track(recording, user2, 'voice', '3c7dcb7c4c35c0bb313fc15ee3e6bfd5', 2244968, 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/track-chris-vox.ogg')
make_recorded_track(recording, user3, 'voice', '10ca4c6ef5b98b3489ae8da1c7fa9cfb', 2254275, 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/track-matt-lead-vox.ogg')
make_recorded_track(recording, user4, 'drums', 'ea366f482fa969e1fd8530c13cb75716', 2386250, 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/track-randy-drum1.ogg')
make_recorded_track(recording, user4, 'drums', '4c693c6e99117719c6340eb68b0fe574', 2566463, 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/track-randy-drum2.ogg')
make_claimed_recording(recording, user1, 'Poison', 'Classic song that you all know -- user1')
make_claimed_recording(recording, user2, 'Poison', 'Classic song that you all know -- user2')
make_claimed_recording(recording, user3, 'Poison', 'Classic song that you all know -- user3')
make_claimed_recording(recording, user4, 'Poison', 'Classic song that you all know -- user4')
mix = Mix.new
mix.started_at = Time.now
mix.completed_at = Time.now
mix[:ogg_url] = 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/master-out.ogg'
mix.ogg_md5 = 'f1fee708264602e1705638e53f0ea667'
mix.ogg_length = 2500633
mix[:mp3_url] = 'https://jamjam:blueberryjam@int.jamkazam.com/stuff/lc_rocks_poison/master-out.mp3'
mix.mp3_md5 = 'df05abad96e5cb8439f7cd6e31b5c503'
mix.mp3_length = 3666137
mix.completed = true
recording.mixes << mix
recording.save!(validate:false)
end

View File

@ -4,11 +4,14 @@ describe ApiFeedsController do
render_views
let(:user) { FactoryGirl.create(:user) }
let(:user2) { FactoryGirl.create(:user) }
let(:band) { FactoryGirl.create(:band) }
let(:music_session) {FactoryGirl.create(:music_session, creator: user) }
let(:claimed_recording) {FactoryGirl.create(:claimed_recording) }
before(:each) do
MusicSession.delete_all
MusicSessionUserHistory.delete_all
MusicSessionHistory.delete_all
Recording.delete_all
end
@ -23,6 +26,7 @@ describe ApiFeedsController do
it "returns a recording" do
claimed_recording.touch
# artifact of factory of :claimed_recording that this gets created
MusicSessionUserHistory.delete_all
MusicSessionHistory.delete_all
get :index
@ -41,11 +45,48 @@ describe ApiFeedsController do
json = JSON.parse(response.body, :symbolize_names => true)
json[:entries].length.should == 1
music_session = json[:entries][0]
music_session[:type].should == 'music_session_history'
end
describe "time range" do
it "today and month find different results" do
music_session.music_session_history.touch
music_session.music_session_history.feed.created_at = 3.days.ago
music_session.music_session_history.feed.save!
get :index
json = JSON.parse(response.body, :symbolize_names => true)
json[:entries].length.should == 1
get :index, { time_range:'today' }
json = JSON.parse(response.body, :symbolize_names => true)
json[:entries].length.should == 0
end
end
describe "type filter" do
it "can filter by type" do
claimed_recording.touch
get :index
json = JSON.parse(response.body, :symbolize_names => true)
json[:entries].length.should == 2
get :index, { type: 'recording'}
json = JSON.parse(response.body, :symbolize_names => true)
json[:entries].length.should == 1
json[:entries][0][:type].should == 'recording'
get :index, { type: 'music_session_history'}
json = JSON.parse(response.body, :symbolize_names => true)
json[:entries].length.should == 1
json[:entries][0][:type].should == 'music_session_history'
end
end
describe "pagination" do
it "since parameter" do
@ -72,4 +113,65 @@ describe ApiFeedsController do
_next.should be_nil
end
end
describe "user targetting" do
it "user viewing own profile" do
music_session.fan_access = false
music_session.save!
controller.current_user = music_session.creator
get :index, { user: music_session.creator.id }
json = JSON.parse(response.body, :symbolize_names => true)
json[:entries].length.should == 1
end
it "user viewing someone else's profile" do
music_session.fan_access = false
music_session.save!
controller.current_user = user2
music_session.music_session_history.reload
music_session.music_session_history.fan_access.should be_false
get :index, { user: music_session.creator.id }
json = JSON.parse(response.body, :symbolize_names => true)
json[:entries].length.should == 0
end
end
describe "band targetting" do
it "user viewing own band" do
user.bands << band
user.save!
claimed_recording1 = FactoryGirl.create(:claimed_recording, user: user)
claimed_recording1.is_public = false
claimed_recording1.recording.band = band
claimed_recording1.recording.save!
claimed_recording1.save!
controller.current_user = user
get :index, { band: band.id }
json = JSON.parse(response.body, :symbolize_names => true)
json[:entries].length.should == 1
end
it "user viewing someone else's band" do
user.bands << band
user.save!
claimed_recording1 = FactoryGirl.create(:claimed_recording, user: user)
claimed_recording1.is_public = false
claimed_recording1.recording.band = band
claimed_recording1.recording.save!
claimed_recording1.save!
controller.current_user = user2
get :index, { band: band.id }
json = JSON.parse(response.body, :symbolize_names => true)
json[:entries].length.should == 0
end
end
end

View File

@ -16,6 +16,9 @@ FactoryGirl.define do
terms_of_service true
subscribe_email true
factory :fan do
musician false
end
factory :admin do
admin true
@ -33,20 +36,6 @@ FactoryGirl.define do
end
end
factory :fan, :class => JamRuby::User do
sequence(:first_name) { |n| "Person" }
sequence(:last_name) { |n| "#{n}" }
sequence(:email) { |n| "fan_#{n}@example.com"}
password "foobar"
password_confirmation "foobar"
email_confirmed true
musician false
city "Apex"
state "NC"
country "US"
terms_of_service true
end
factory :invited_user, :class => JamRuby::InvitedUser do
sequence(:email) { |n| "user#{n}@someservice.com" }
autofriend false
@ -63,12 +52,20 @@ FactoryGirl.define do
association :creator, :factory => :user
after(:create) { |session|
MusicSessionHistory.save(session)
FactoryGirl.create(:music_session_user_history, :history => session.music_session_history, :user => session.creator)
}
end
factory :music_session_user_history, :class => JamRuby::MusicSessionUserHistory do
ignore do
history nil
user nil
end
music_session_id { history.music_session_id }
user_id { user.id }
sequence(:client_id) { |n| "Connection #{n}" }
end
@ -92,6 +89,9 @@ FactoryGirl.define do
city "Apex"
state "NC"
country "US"
before(:create) { |band|
band.genres << Genre.first
}
end
factory :join_request, :class => JamRuby::JoinRequest do

View File

@ -4,10 +4,18 @@ describe "Bands", :js => true, :type => :feature, :capybara_feature => true do
subject { page }
before(:all) do
Capybara.javascript_driver = :poltergeist
Capybara.current_driver = Capybara.javascript_driver
Capybara.default_wait_time = 15
MaxMindIsp.delete_all # prove that city/state/country will remain nil if no maxmind data
MaxMindGeo.delete_all
MaxMindManager.active_record_transaction do |manager|
manager.create_phony_database()
end
end
let(:user) { FactoryGirl.create(:user) }
@ -15,9 +23,10 @@ describe "Bands", :js => true, :type => :feature, :capybara_feature => true do
before(:each) do
UserMailer.deliveries.clear
navigate_band_setup
end
it "band setup is accessible through profile page" do
def navigate_band_setup
sign_in_poltergeist(user)
wait_until_curtain_gone
find('div.homecard.profile').trigger(:click)
@ -26,6 +35,25 @@ describe "Bands", :js => true, :type => :feature, :capybara_feature => true do
expect(page).to have_selector('#band-setup-title')
end
it "have validation errors shown, but then can navigate past and eventually save" do
find('#btn-band-setup-next').trigger(:click)
find('#tdBandName .error-text li', text: "can't be blank")
find('#tdBandBiography .error-text li', text: "can't be blank")
find('#tdBandGenres .error-text li', text: "At least 1 genre is required.")
within('#band-setup-form') do
fill_in "band-name", with: "The Band"
fill_in "band-biography", with: "Biography"
first('#band-genres input[type="checkbox"]').trigger(:click)
end
find('#btn-band-setup-next').trigger(:click)
find('h2', text: 'Step 2: Add Band Members')
find('#btn-band-setup-save').trigger(:click)
find('#band-profile-name', text: "The Band")
find('#band-profile-biography', text: "Biography")
end
end

View File

@ -28,6 +28,8 @@ describe "Musician Search", :js => true, :type => :feature, :capybara_feature =>
end
it "shows blank result set" do
pending "fails intermittently on build server"
wait_for_easydropdown('#musician_instrument')
# get the 2nd option from the instruments list
text = find('#musician_instrument', :visible => false).find(:xpath, 'option[2]', :visible => false).text

View File

@ -63,6 +63,7 @@ describe "Home Screen", :js => true, :type => :feature, :capybara_feature => tru
# needed because we poke the server with an updateUser call, but their is no indication in the UI that it's done
wait_for_ajax
page.driver.headers = { 'User-Agent' => ' JamKazam ' }
sleep 1
visit "/client"
wait_until_curtain_gone
should_not have_selector('h1', text: 'what\'s next?')

View File

@ -10,6 +10,16 @@ describe "Band API", :type => :api do
let(:band) { FactoryGirl.create(:band) }
let(:user) { FactoryGirl.create(:user) }
let(:fan) { FactoryGirl.create(:fan) }
let(:band_params) {
{
name: "My Band",
biography: "Biography",
city: 'Austin',
state: 'TX',
country: 'US',
genres: ['rock']
}
}
def login(email, password, http_code, success)
# login as fan
@ -19,45 +29,33 @@ describe "Band API", :type => :api do
end
################################## BANDS ##################################
def create_band(authenticated_user, name, website, biography, city, state, country, genres, photo_url, logo_url)
post "/api/bands.json", { :name => name,
:website => website,
:biography => biography,
:city => city,
:state => state,
:country => country,
:genres => genres,
:photo_url => photo_url,
:logo_url => logo_url
}.to_json,
"CONTENT_TYPE" => 'application/json'
return last_response
def create_band(authenticated_user, options={})
options = band_params.merge(options)
post "/api/bands.json", options.to_json, "CONTENT_TYPE" => 'application/json'
last_response
end
def update_band(authenticated_user, band_id, name, website, biography, city, state, country, genres, photo_url, logo_url)
post "/api/bands/#{band_id}.json", { :name => name,
:website => website,
:biography => biography,
:city => city,
:state => state,
:country => country,
:genres => genres,
:photo_url => photo_url,
:logo_url => logo_url
}.to_json,
"CONTENT_TYPE" => 'application/json'
return last_response
def validate_band(authenticated_user, options={})
options = band_params.merge(options)
post "/api/bands/validate.json", options.to_json, "CONTENT_TYPE" => 'application/json'
last_response
end
def update_band(authenticated_user, band_id, options={})
options = band_params.merge(options)
post "/api/bands/#{band_id}.json", options.to_json, "CONTENT_TYPE" => 'application/json'
last_response
end
def get_band(authenticated_user, band_id)
get "/api/bands/#{band_id}.json", "CONTENT_TYPE" => 'application/json'
return last_response
last_response
end
########################## RECORDINGS #########################
def create_band_recording(authenticated_user, band_id, description, public, genres)
post "/api/bands/#{band_id}/recordings.json", { :description => description, :public => public, :genres => genres }.to_json, "CONTENT_TYPE" => 'application/json'
return last_response
last_response
end
def update_band_recording()
@ -98,9 +96,19 @@ describe "Band API", :type => :api do
login(user.email, user.password, 200, true)
end
it "should pass validation" do
last_response = validate_band(user)
last_response.status.should == 200
end
it "should fail validation" do
last_response = validate_band(user, name: nil)
last_response.status.should == 422
end
it "should allow band creation" do
last_response = create_band(user, "My Band", "http://www.myband.com", "Bio", "Apex", "NC", "US", ["country"], "www.photos.com", "www.logos.com")
last_response = create_band(user)
last_response.status.should == 201
new_band = JSON.parse(last_response.body)
@ -117,17 +125,17 @@ describe "Band API", :type => :api do
end
it "should prevent bands with less than 1 genre" do
last_response = create_band(user, "My Band", "http://www.myband.com", "Bio", "Apex", "NC", "US", nil, "www.photos.com", "www.logos.com")
last_response.status.should == 400
last_response = create_band(user, genres: [])
last_response.status.should == 422
error_msg = JSON.parse(last_response.body)
error_msg["message"].should == ValidationMessages::GENRE_MINIMUM_NOT_MET
error_msg["errors"]["genres"].should == [ValidationMessages::BAND_GENRE_MINIMUM_NOT_MET]
end
it "should prevent bands with more than 3 genres" do
last_response = create_band(user, "My Band", "http://www.myband.com", "Bio", "Apex", "NC", "US", ["african", "country", "ambient", "asian"], "www.photos.com", "www.logos.com")
last_response.status.should == 400
last_response = create_band(user, genres: ["african", "country", "ambient", "asian"])
last_response.status.should == 422
error_msg = JSON.parse(last_response.body)
error_msg["message"].should == ValidationMessages::GENRE_LIMIT_EXCEEDED
error_msg["errors"]["genres"].should == [ValidationMessages::BAND_GENRE_LIMIT_EXCEEDED]
end
end
@ -135,9 +143,6 @@ describe "Band API", :type => :api do
before(:each) do
login(user.email, user.password, 200, true)
band.genres << Genre.find("hip hop")
#band.genres << Genre.find("african")
#band.genres << Genre.find("country")
user.bands << band
end
@ -145,7 +150,7 @@ describe "Band API", :type => :api do
band.genres.size.should == 1
last_response = update_band(user, band.id, "Brian's Band", "http://www.briansband.com", "Bio", "Apex", "NC", "US", ["african"], "www.photos.com", "www.logos.com")
last_response = update_band(user, band.id, name: "Brian's Band", website: "http://www.briansband.com", genres: ["african"])
last_response.status.should == 200
updated_band = JSON.parse(last_response.body)
@ -161,8 +166,8 @@ describe "Band API", :type => :api do
band_details = JSON.parse(last_response.body)
band_details["name"].should == "Brian's Band"
band_details["website"].should == "http://www.briansband.com"
band_details["biography"].should == "Bio"
band_details["genres"].size.should == 1
band_details["biography"].should == "Biography"
band_details["genres"].should == [{"id"=>"african", "description"=>"African"}]
end
it "should allow user to create recording for band A" do

View File

@ -7,6 +7,16 @@ describe "Search API", :type => :api do
describe "profile page" do
let(:user) { FactoryGirl.create(:user) }
let(:band_params) {
{
name: "The Band",
biography: "Biography",
city: 'Austin',
state: 'TX',
country: 'US',
genres: ['country']
}
}
before(:each) do
post '/sessions', "session[email]" => user.email, "session[password]" => user.password
@ -22,8 +32,10 @@ describe "Search API", :type => :api do
it "simple search" do
@musician = FactoryGirl.create(:user, first_name: "Peach", last_name: "Nothing", email: "user@example.com", musician: true)
@fan = FactoryGirl.create(:user, first_name: "Peach Peach", last_name: "Grovery", email: "fan@example.com", musician: false)
@band = Band.save(nil, "Peach pit", "www.bands.com", "zomg we rock", "Apex", "NC", "US", ["hip hop"], user.id, nil, nil)
@band2 = Band.save(nil, "Peach", "www.bands2.com", "zomg we rock", "Apex", "NC", "US", ["hip hop"], user.id, nil, nil)
band_params[:name] = "Peach pit"
@band = Band.save(user, band_params)
band_params[:name] = "Peach"
@band2 = Band.save(user, band_params)
get '/api/search.json?query=peach&search_text_type=bands'
last_response.status.should == 200

View File

@ -19,9 +19,12 @@ db_config = YAML::load(File.open('config/database.yml'))["test"]
# initialize ActiveRecord's db connection\
SpecDb::recreate_database(db_config)
ActiveRecord::Base.establish_connection(YAML::load(File.open('config/database.yml'))["test"])
require 'jam_ruby'
# uncomment this to see active record logs
# ActiveRecord::Base.logger = Logger.new(STDOUT) if defined?(ActiveRecord::Base)
include JamRuby
# put ActionMailer into test mode
@ -51,7 +54,6 @@ Spork.prefork do
Capybara.default_wait_time = 10
if defined?(TEST_CONNECT_STATES) && TEST_CONNECT_STATES
require 'capybara/poltergeist'
TEST_CONNECT_STATE_JS_CONSOLE_IO = File.open(TEST_CONNECT_STATE_JS_CONSOLE, 'w')
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, { phantomjs_logger: TEST_CONNECT_STATE_JS_CONSOLE_IO })
@ -134,8 +136,8 @@ Spork.prefork do
# dump response.body if an example fails
if example.metadata[:type] == :controller && example.exception
puts "'#{determine_test_name(example.metadata)}' controller test failed."
puts "response.status = #{response.status}, response.body = " + response.body
puts "'#{determine_test_name(example.metadata)}' controller test failed."
puts "response.status = #{response.status}, response.body = " + response.body
end
end

View File

@ -56,8 +56,8 @@ end
def sign_in_poltergeist(user)
visit signin_path
fill_in "Email Address:", with: user.email
fill_in "Password:", with: user.password
fill_in "session_email", with: user.email
fill_in "session_password", with: user.password
click_button "SIGN IN"
if Capybara.javascript_driver == :poltergeist