diff --git a/lib/jam_ruby.rb b/lib/jam_ruby.rb index 482976feb..4369cf807 100644 --- a/lib/jam_ruby.rb +++ b/lib/jam_ruby.rb @@ -8,6 +8,8 @@ require "will_paginate" require "will_paginate/active_record" require "action_mailer" require "sendgrid" +require "jam_ruby/constants/validation_messages" +require "jam_ruby/constants/limits" require "jam_ruby/errors/permission_error" require "jam_ruby/errors/state_error" require "jam_ruby/errors/jam_argument_error" @@ -25,6 +27,10 @@ require "jam_ruby/models/user" require "jam_ruby/models/user_authorization" require "jam_ruby/models/join_request" require "jam_ruby/models/band" +require "jam_ruby/models/band_recording" +require "jam_ruby/models/band_invitation" +require "jam_ruby/models/band_follower" +require "jam_ruby/models/band_musician" require "jam_ruby/models/connection" require "jam_ruby/models/friendship" require "jam_ruby/models/music_session" @@ -32,15 +38,14 @@ require "jam_ruby/models/invitation" require "jam_ruby/models/fan_invitation" require "jam_ruby/models/friend_request" require "jam_ruby/models/instrument" -require "jam_ruby/models/connection_track" require "jam_ruby/models/musician_instrument" -require "jam_ruby/models/band_musician" +require "jam_ruby/models/connection_track" require "jam_ruby/models/user_follower" require "jam_ruby/models/user_following" require "jam_ruby/models/user_favorite" -require "jam_ruby/models/band_follower" require "jam_ruby/models/search" require "jam_ruby/models/recording" +require "jam_ruby/models/musician_recording" include Jampb diff --git a/lib/jam_ruby/base_manager.rb b/lib/jam_ruby/base_manager.rb index 1e3ad0747..5da4b3b0a 100644 --- a/lib/jam_ruby/base_manager.rb +++ b/lib/jam_ruby/base_manager.rb @@ -12,8 +12,8 @@ module JamRuby end end - # Creates a connection manager, and associates the connection created by active_record with ourselves - def self.active_record_transaction(&block) + # Creates a connection manager, and associates the connection created by active_record with ourselves + def self.active_record_transaction manager = self.new ActiveRecord::Base.connection_pool.with_connection do |connection| @@ -23,7 +23,7 @@ module JamRuby manager.pg_conn = connection.instance_variable_get("@connection") connection.transaction do - block.call(manager) + yield manager end end end diff --git a/lib/jam_ruby/constants/limits.rb b/lib/jam_ruby/constants/limits.rb new file mode 100644 index 000000000..63e731356 --- /dev/null +++ b/lib/jam_ruby/constants/limits.rb @@ -0,0 +1,11 @@ +module Limits + + # genres + MIN_GENRES_PER_BAND = 1 + MAX_GENRES_PER_BAND = 3 + + # instruments + MIN_INSTRUMENTS_PER_MUSICIAN = 1 + MAX_INSTRUMENTS_PER_MUSICIAN = 5 + +end \ No newline at end of file diff --git a/lib/jam_ruby/constants/validation_messages.rb b/lib/jam_ruby/constants/validation_messages.rb new file mode 100644 index 000000000..a6e08575b --- /dev/null +++ b/lib/jam_ruby/constants/validation_messages.rb @@ -0,0 +1,22 @@ +module ValidationMessages + + # general messages + PERMISSION_VALIDATION_ERROR = "You do not have permissions to perform this action." + USER_NOT_MUSICIAN_VALIDATION_ERROR = "You must be a Musician to perform this action." + USER_NOT_BAND_MEMBER_VALIDATION_ERROR = "You must be a band member to perform this action." + + # band invitations + BAND_INVITATION_NOT_FOUND = "Band invitation not found." + + # recordings + RECORDING_NOT_FOUND = "Recording not found." + + # genres + GENRE_LIMIT_EXCEEDED = "No more than 3 genres are allowed." + GENRE_MINIMUM_NOT_MET = "At least 1 genre is required." + + # instruments + INSTRUMENT_LIMIT_EXCEEDED = "No more than 5 instruments are allowed." + INSTRUMENT_MINIMUM_NOT_MET = "At least 1 instrument is required." + +end \ No newline at end of file diff --git a/lib/jam_ruby/models/band.rb b/lib/jam_ruby/models/band.rb index 24a8c6a4f..091815192 100644 --- a/lib/jam_ruby/models/band.rb +++ b/lib/jam_ruby/models/band.rb @@ -3,7 +3,7 @@ module JamRuby include Tire::Model::Search include Tire::Model::Callbacks - attr_accessible :name, :website, :biography + attr_accessible :name, :website, :biography, :city, :state, :country self.primary_key = 'id' @@ -15,7 +15,8 @@ module JamRuby has_and_belongs_to_many :genres, :class_name => "JamRuby::Genre", :join_table => "bands_genres" # recordings - has_and_belongs_to_many :recordings, :class_name => "JamRuby::Recording", :join_table => "bands_recordings" + has_many :band_recordings, :class_name => "JamRuby::BandRecording", :foreign_key => "band_id" + has_many :recordings, :through => :band_recordings, :class_name => "JamRuby::Recording" # followers has_many :followers, :class_name => "JamRuby::BandFollower", :foreign_key => "band_id" @@ -36,6 +37,9 @@ module JamRuby @logo_url = "http://www.jamkazam.com/images/bands/logos/#{self.id}.gif" end + # invitations + has_many :invitations, :inverse_of => :band, :class_name => "JamRuby::BandInvitation", :foreign_key => "band_id" + def follower_count return self.followers.size end @@ -45,47 +49,69 @@ module JamRuby # this will be indexed into elasticsearch and returned in search return "#{self.city}, #{self.state}, #{self.country}" end + + def add_member(user_id, admin) + BandMusician.create(:band_id => self.id, :user_id => user_id, :admin => admin) + end # helper method for creating / updating a Band - def self.save(params) - if params[:id].nil? + def self.save(id, name, website, biography, city, state, country, genres, user_id, photo_url, logo_url) + + user = User.find(user_id) + + # new band + if id.nil? + + # 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 - band = Band.find(params[:id]) + 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 end # name - unless params[:name].nil? - band.name = params[:name] + unless name.nil? + band.name = name end # website - unless params[:website].nil? - band.website = params[:website] - end + unless website.nil? + band.website = website + end # biography - unless params[:biography].nil? - band.biography = params[:biography] + unless biography.nil? + band.biography = biography end # city - unless params[:city].nil? - band.city = params[:city] + unless city.nil? + band.city = city end # state - unless params[:state].nil? - band.state = params[:state] + unless state.nil? + band.state = state end # country - unless params[:country].nil? - band.country = params[:country] + unless country.nil? + band.country = country end # genres - genres = params[:genres] unless genres.nil? ActiveRecord::Base.transaction do # delete all genres for this band first @@ -101,18 +127,27 @@ module JamRuby end end + # photo url + unless photo_url.nil? + band.photo_url = photo_url + end + + # logo url + unless logo_url.nil? + band.logo_url = logo_url + end + band.updated_at = Time.now.getutc band.save + + # add the creator as the admin + if id.nil? + BandMusician.create(:band_id => band.id, :user_id => user_id, :admin => true) + end + return band end - def limit_to_three_genres - if self.genres.count > 3 - errors.add(:genres, "No more than 3 genres are allowed.") - end - end - - ### Elasticsearch/Tire integration ### # # Define the name based on the environment @@ -138,7 +173,7 @@ module JamRuby :mappings => { "jam_ruby/band" => { :properties => { - :logo_url => { :type => :string, :index => :not_analyzed, :include_in_all => false }, + :logo_url => { :type => :string, :index => :not_analyzed, :include_in_all => false }, :photo_url => { :type => :string, :index => :not_analyzed, :include_in_all => false}, :name => { :type => :string, :boost => 100}, :location => { :type => :string }, @@ -158,5 +193,24 @@ module JamRuby end end ### Elasticsearch/Tire integration + + private + def self.validate_genres(genres, is_nil_ok) + if is_nil_ok && genres.nil? + return + 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 + end + end end end diff --git a/lib/jam_ruby/models/band_invitation.rb b/lib/jam_ruby/models/band_invitation.rb new file mode 100644 index 000000000..94a830fd3 --- /dev/null +++ b/lib/jam_ruby/models/band_invitation.rb @@ -0,0 +1,45 @@ +module JamRuby + class BandInvitation < ActiveRecord::Base + + self.table_name = "band_invitations" + + self.primary_key = 'id' + + belongs_to :receiver, :inverse_of => :received_band_invitations, :foreign_key => "user_id", :class_name => "JamRuby::User" + belongs_to :sender, :inverse_of => :sent_band_invitations, :foreign_key => "creator_id", :class_name => "JamRuby::User" + belongs_to :band, :inverse_of => :invitations, :foreign_key => "band_id", :class_name => "JamRuby::Band" + + def self.save(id, band_id, user_id, creator_id, accepted) + + # ensure certain fields are only updated on creation + if id.nil? + # ensure recipient is a Musician + user = User.find(user_id) + unless user.musician? + raise JamRuby::JamArgumentError, "A Band invitation can only be sent to a Musician." + end + + band_invitation = BandInvitation.new() + band_invitation.band_id = band_id + band_invitation.user_id = user_id + band_invitation.creator_id = creator_id + + # only the accepted flag can be updated after initial creation + else + band_invitation = BandInvitation.find(id) + band_invitation.accepted = accepted + end + + band_invitation.updated_at = Time.now.getutc + band_invitation.save + + # TODO: wrap this and previous block in transaction + # accepting an invitation adds the musician to the band + if accepted + BandMusician.create(:band_id => band_invitation.band.id, :user_id => band_invitation.receiver.id, :admin => false) + end + + return band_invitation + end + end +end \ No newline at end of file diff --git a/lib/jam_ruby/models/band_musician.rb b/lib/jam_ruby/models/band_musician.rb index a750bafe4..91cc54c11 100644 --- a/lib/jam_ruby/models/band_musician.rb +++ b/lib/jam_ruby/models/band_musician.rb @@ -3,6 +3,8 @@ module JamRuby self.table_name = "bands_musicians" + attr_accessible :band_id, :user_id, :admin + self.primary_key = 'id' belongs_to :user diff --git a/lib/jam_ruby/models/band_recording.rb b/lib/jam_ruby/models/band_recording.rb new file mode 100644 index 000000000..958dcd973 --- /dev/null +++ b/lib/jam_ruby/models/band_recording.rb @@ -0,0 +1,14 @@ +module JamRuby + class BandRecording < ActiveRecord::Base + + self.table_name = "bands_recordings" + + attr_accessible :band_id, :recording_id + + # bands + has_many :bands, :through => :band_recordings, :class_name => "JamRuby::Band" + + belongs_to :band, :class_name => "JamRuby::Band", :foreign_key => "band_id" + belongs_to :recording, :class_name => "JamRuby::Recording", :foreign_key => "recording_id" + end +end \ No newline at end of file diff --git a/lib/jam_ruby/models/instrument.rb b/lib/jam_ruby/models/instrument.rb index 4af0dd1ae..e0563c454 100644 --- a/lib/jam_ruby/models/instrument.rb +++ b/lib/jam_ruby/models/instrument.rb @@ -4,7 +4,7 @@ module JamRuby self.primary_key = 'id' # users - has_many :musician_instruments + has_many :musician_instruments, :class_name => "JamRuby::MusicianInstrument" has_many :users, :through => :musician_instruments, :class_name => "JamRuby::User" has_many :connection_tracks, :class_name => "JamRuby::ConnectionTrack", :inverse_of => :instrument diff --git a/lib/jam_ruby/models/music_session.rb b/lib/jam_ruby/models/music_session.rb index f5e1d2a28..2b9a96300 100644 --- a/lib/jam_ruby/models/music_session.rb +++ b/lib/jam_ruby/models/music_session.rb @@ -91,14 +91,14 @@ module JamRuby private def require_at_least_one_genre - if genres.count == 0 - errors.add(:genres, "Please select at least one genre") + if genres.count < Limits::MIN_GENRES_PER_BAND + errors.add(:genres, ValidationMessages::GENRE_MINIMUM_NOT_MET) end end def limit_to_three_genres - if genres.count > 3 - errors.add(:genres, "Three genres at most, please") + if genres.count > Limits::MAX_GENRES_PER_BAND + errors.add(:genres, ValidationMessages::GENRE_LIMIT_EXCEEDED) end end end diff --git a/lib/jam_ruby/models/musician_instrument.rb b/lib/jam_ruby/models/musician_instrument.rb index 2fd11e64e..4ce963dcf 100644 --- a/lib/jam_ruby/models/musician_instrument.rb +++ b/lib/jam_ruby/models/musician_instrument.rb @@ -5,8 +5,8 @@ module JamRuby self.primary_key = 'id' - belongs_to :user - belongs_to :instrument + belongs_to :user, :class_name => "JamRuby::User" + belongs_to :instrument, :class_name => "JamRuby::Instrument" def description @description = self.instrument.description diff --git a/lib/jam_ruby/models/musician_recording.rb b/lib/jam_ruby/models/musician_recording.rb new file mode 100644 index 000000000..30293ce6c --- /dev/null +++ b/lib/jam_ruby/models/musician_recording.rb @@ -0,0 +1,14 @@ +module JamRuby + class MusicianRecording < ActiveRecord::Base + + self.table_name = "musicians_recordings" + + attr_accessible :user_id, :recording_id + + # musicians + has_many :musicians, :through => :musician_recordings, :class_name => "JamRuby::User" + + belongs_to :user, :class_name => "JamRuby::User", :foreign_key => "user_id" + belongs_to :recording, :class_name => "JamRuby::Recording", :foreign_key => "recording_id" + end +end \ No newline at end of file diff --git a/lib/jam_ruby/models/recording.rb b/lib/jam_ruby/models/recording.rb index 2f253a04d..1cf46ca63 100644 --- a/lib/jam_ruby/models/recording.rb +++ b/lib/jam_ruby/models/recording.rb @@ -3,11 +3,88 @@ module JamRuby self.primary_key = 'id' - # musicians - has_and_belongs_to_many :users, :class_name => "JamRuby::User", :join_table => "musicians_recordings" + has_many :musician_recordings, :class_name => "JamRuby::MusicianRecording" + has_many :band_recordings, :class_name => "JamRuby::BandRecording" - # bands - has_and_belongs_to_many :bands, :class_name => "JamRuby::Band", :join_table => "bands_recordings" + # favorites + has_and_belongs_to_many :user_favorites, :class_name => "JamRuby::UserFavorite", :join_table => "users_favorites" + validates :description, presence: true, length: { maximum: 200 } + + def self.save(id, is_public, description, updater_id, owner_id, is_band) + + creator = User.find(updater_id) + + if is_band + band = Band.find(owner_id) + validate_user_is_band_member(creator, band) + else + user = User.find(owner_id) + validate_user_is_creator(user, creator) + validate_user_is_musician(user) + end + + if id.nil? + recording = Recording.new() + recording.creator_id = updater_id + else + recording = Recording.find(id) + end + + recording.updater_id = updater_id + + # public flag + unless is_public.nil? + recording.public = is_public + end + + # description + unless description.nil? + recording.description = description + end + + recording.updated_at = Time.now.getutc + + # TODO: wrap in transaction with statements below + recording.save + + if id.nil? + if is_band + recording.band_recordings << BandRecording.create(band_id: owner_id, recording_id: recording.id) + else + recording.musician_recordings << MusicianRecording.create(user_id: owner_id, recording_id: recording.id) + end + end + + return recording + end + + private + def self.validate_user_is_band_member(user, band) + unless band.users.exists? user + raise PermissionError, ValidationMessages::USER_NOT_BAND_MEMBER_VALIDATION_ERROR + end + end + + def self.validate_user_is_creator(user, creator) + unless user.id == creator.id + raise PermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR + end + end + + def self.validate_user_is_musician(user) + unless user.musician? + raise PermissionError, ValidationMessages::USER_NOT_MUSICIAN_VALIDATION_ERROR + end + end + +=begin + def self.delete(id, owner_id, is_band) + if is_band? + JamRuby::Recording.delete_all "(user_id = '#{user_id}' AND follower_id = '#{follower_id}')" + else + end + end +=end end end \ No newline at end of file diff --git a/lib/jam_ruby/models/user.rb b/lib/jam_ruby/models/user.rb index aac63a509..a23833464 100644 --- a/lib/jam_ruby/models/user.rb +++ b/lib/jam_ruby/models/user.rb @@ -9,9 +9,6 @@ module JamRuby # authorizations (for facebook, etc -- omniauth) has_many :user_authorizations, :class_name => "JamRuby::UserAuthorization" - - # account - belongs_to :account, :class_name => "JamRuby::Account" # connections (websocket-gateway) has_many :connections, :class_name => "JamRuby::Connection" @@ -20,15 +17,16 @@ module JamRuby has_many :friend_requests, :class_name => "JamRuby::FriendRequest" # instruments - has_many :musician_instruments + has_many :musician_instruments, :class_name => "JamRuby::MusicianInstrument" has_many :instruments, :through => :musician_instruments, :class_name => "JamRuby::Instrument" # bands - has_many :band_musicians + has_many :band_musicians, :class_name => "JamRuby::BandMusician" has_many :bands, :through => :band_musicians, :class_name => "JamRuby::Band" # recordings - has_and_belongs_to_many :recordings, :class_name => "JamRuby::Recording", :join_table => "musicians_recordings" + has_many :musician_recordings, :class_name => "JamRuby::MusicianRecording", :foreign_key => "user_id" + has_many :recordings, :through => :musician_recordings, :class_name => "JamRuby::Recording" # followers has_many :followers, :class_name => "JamRuby::UserFollower", :foreign_key => "user_id" @@ -43,8 +41,8 @@ module JamRuby has_many :inverse_band_followings, :through => :band_followings, :class_name => "JamRuby::Band", :foreign_key => "band_id" # favorites - has_many :favorites, :class_name => "JamRuby::UserFavorite", :foreign_key => "recording_id" - has_many :inverse_favorites, :through => :favorites, :source => :user, :class_name => "JamRuby::User", :foreign_key => "user_id" + has_many :favorites, :class_name => "JamRuby::UserFavorite", :foreign_key => "user_id" + has_many :inverse_favorites, :through => :favorites, :source => :user, :class_name => "JamRuby::User" # friends has_many :friendships, :class_name => "JamRuby::Friendship", :foreign_key => "user_id" @@ -60,18 +58,20 @@ module JamRuby has_many :received_invitations, :foreign_key => "receiver_id", :inverse_of => :receiver, :class_name => "JamRuby::Invitation" has_many :sent_invitations, :foreign_key => "sender_id", :inverse_of => :sender, :class_name => "JamRuby::Invitation" - # fan_invitations + # fan invitations has_many :received_fan_invitations, :foreign_key => "receiver_id", :inverse_of => :receiver, :class_name => "JamRuby::FanInvitation" has_many :sent_fan_invitations, :foreign_key => "sender_id", :inverse_of => :sender, :class_name => "JamRuby::FanInvitation" + # band invitations + has_many :received_band_invitations, :inverse_of => :receiver, :foreign_key => "user_id", :class_name => "JamRuby::BandInvitation" + has_many :sent_band_invitations, :inverse_of => :sender, :foreign_key => "creator_id", :class_name => "JamRuby::BandInvitation" + # This causes the authenticate method to be generated (among other stuff) has_secure_password before_save { |user| user.email = email.downcase } before_save :create_remember_token - after_save :limit_to_five_instruments - validates :first_name, presence: true, length: {maximum: 50} validates :last_name, presence: true, length: {maximum: 50} VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i @@ -87,11 +87,6 @@ module JamRuby @online ||= !self.connections.nil? && self.connections.size > 0 end - def photo_url - # TODO: move image path to config - @photo_url = "http://www.jamkazam.com/images/users/photos/#{self.id}.gif"; - end - def name return "#{first_name} #{last_name}" end @@ -119,6 +114,14 @@ module JamRuby def following_count return self.followings.size + self.band_followings.size end + + def confirm_email! + self.email_confirmed = true + end + + def favorite_count + return self.favorites.size + end def to_s return email unless email.nil? @@ -131,199 +134,236 @@ module JamRuby end # helper method for creating / updating a User - def self.save(params) - if params[:id].nil? + def self.save(id, updater_id, first_name, last_name, email, password, password_confirmation, musician, gender, + birth_date, internet_service_provider, city, state, country, instruments, photo_url) + if id.nil? + validate_instruments(instruments, musician) user = User.new() else - user = User.find(params[:id]) + validate_instruments(instruments, true) + user = User.find(id) end - # account id - unless params[:account_id].nil? - user.account_id = params[:account_id] - end + if user.id != updater_id + raise PermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR + end # first name - unless params[:first_name].nil? - user.first_name = params[:first_name] + unless first_name.nil? + user.first_name = first_name end # last name - unless params[:last_name].nil? - user.last_name = params[:last_name] + unless last_name.nil? + user.last_name = last_name end # email - unless params[:email].nil? - user.email = params[:email] + unless email.nil? + user.email = email end # password - unless params[:password].nil? - user.password = params[:password] + unless password.nil? + user.password = password end # password confirmation - unless params[:password_confirmation].nil? - user.password_confirmation = params[:password_confirmation] + unless password_confirmation.nil? + user.password_confirmation = password_confirmation end # musician flag - unless params[:musician].nil? - user.musician = params[:musician] + unless musician.nil? + user.musician = musician end # gender - unless params[:gender].nil? - account.gender = params[:gender] + unless gender.nil? + account.gender = gender end # birthdate - unless params[:birth_date].nil? - account.birth_date = params[:birth_date] + unless birth_date.nil? + account.birth_date = birth_date end # ISP - unless params[:internet_service_provider].nil? - account.internet_service_provider = params[:internet_service_provider] + unless internet_service_provider.nil? + account.internet_service_provider = internet_service_provider end # city - unless params[:city].nil? - user.city = params[:city] + unless city.nil? + user.city = city end # state - unless params[:state].nil? - user.state = params[:state] + unless state.nil? + user.state = state end # country - unless params[:country].nil? - user.country = params[:country] + unless country.nil? + user.country = country end # instruments - unless params[:instruments].nil? - ActiveRecord::Base.transaction do + unless instruments.nil? + UserManager.active_record_transaction do |user_manager| # delete all instruments for this user first unless user.id.nil? || user.id.length == 0 MusicianInstrument.delete_all(["user_id = ?", user.id]) end # loop through each instrument in the array and save to the db - params[:instruments].each do |instrument| - mu = MusicianInstrument.new() - mu.user_id = user.id - mu.instrument_id = instrument[:id] - mu.priority = instrument[:priority] - mu.proficiency_level = instrument[:proficiency_level] - user.musician_instruments << mu + instruments.each do |musician_instrument_param| + instrument = Instrument.find(musician_instrument_param[:instrument_id]) + musician_instrument = MusicianInstrument.new + musician_instrument.user = user + musician_instrument.instrument = instrument + musician_instrument.proficiency_level = musician_instrument_param[:proficiency_level] + musician_instrument.priority = musician_instrument_param[:priority] + musician_instrument.save + user.musician_instruments << musician_instrument end end end + # photo url + unless photo_url.nil? + user.photo_url = photo_url + end + user.updated_at = Time.now.getutc user.save return user end - def limit_to_five_instruments - if instruments.count > 5 - errors.add(:instruments, "No more than 5 instruments are allowed.") - end + def self.create_user_following(user_id, follower_id) + follower = UserFollower.new() + follower.user_id = user_id + follower.follower_id = follower_id + follower.save end + def self.delete_user_following(user_id, follower_id) + JamRuby::UserFollower.delete_all "(user_id = '#{user_id}' AND follower_id = '#{follower_id}')" + end - # throws ActiveRecord::RecordNotFound if instrument is invalid - # throws an email delivery error if unable to connect out to SMTP - def self.signup(first_name, last_name, email, password, password_confirmation, - city, state, country, instruments, signup_confirm_url) - user = User.new + def self.create_band_following(band_id, follower_id) + follower = BandFollower.new() + follower.band_id = band_id + follower.follower_id = follower_id + follower.save + end - UserManager.active_record_transaction do |user_manager| - user.first_name = first_name - user.last_name = last_name - user.email = email + def self.delete_band_following(band_id, follower_id) + JamRuby::BandFollower.delete_all "(band_id = '#{band_id}' AND follower_id = '#{follower_id}')" + end - #FIXME: Setting random password for social network logins. This - # is because we have validations all over the place on this. - # The right thing would be to have this null - if password.nil? - user.password = "blahblahblah" - user.password_confirmation = "blahblahblah" - else - user.password = password - user.password_confirmation = password_confirmation - end + def self.create_favorite(user_id, recording_id) + favorite = UserFavorite.new() + favorite.user_id = user_id + favorite.recording_id = recording_id + favorite.save + end - user.admin = false - user.email_confirmed = false - user.city = city - user.state = state - user.country = country - unless instruments.nil? - instruments.each do |musician_instrument_param| - instrument = Instrument.find(musician_instrument_param[:instrument_id]) - musician_instrument = MusicianInstrument.new - musician_instrument.user = user - musician_instrument.instrument = instrument - musician_instrument.proficiency_level = musician_instrument_param[:proficiency_level] - musician_instrument.priority = musician_instrument_param[:priority] - musician_instrument.save - user.musician_instruments << musician_instrument + def self.delete_favorite(user_id, recording_id) + JamRuby::UserFavorite.delete_all "(user_id = '#{user_id}' AND recording_id = '#{recording_id}')" + end + + # throws ActiveRecord::RecordNotFound if instrument is invalid + # throws an email delivery error if unable to connect out to SMTP + def self.signup(first_name, last_name, email, password, password_confirmation, + city, state, country, instruments, photo_url, signup_confirm_url) + user = User.new + + UserManager.active_record_transaction do |user_manager| + user.first_name = first_name + user.last_name = last_name + user.email = email + + #FIXME: Setting random password for social network logins. This + # is because we have validations all over the place on this. + # The right thing would be to have this null + if password.nil? + user.password = "blahblahblah" + user.password_confirmation = "blahblahblah" + else + user.password = password + user.password_confirmation = password_confirmation + end + + user.admin = false + user.email_confirmed = false + user.city = city + user.state = state + user.country = country + unless instruments.nil? + instruments.each do |musician_instrument_param| + instrument = Instrument.find(musician_instrument_param[:instrument_id]) + musician_instrument = MusicianInstrument.new + musician_instrument.user = user + musician_instrument.instrument = instrument + musician_instrument.proficiency_level = musician_instrument_param[:proficiency_level] + musician_instrument.priority = musician_instrument_param[:priority] + musician_instrument.save + user.musician_instruments << musician_instrument + end + end + + user.photo_url = photo_url + + user.signup_token = SecureRandom.urlsafe_base64 + + user.save + + if user.errors.any? + raise ActiveRecord::Rollback + else + # FIXME: + # It's not standard to require a confirmation when a user signs up with Facebook. + # We should stop asking for it. + # + # any errors here should also rollback the transaction; that's OK. If emails aren't going to be delivered, + # it's already a really bad situation; make user signup again + UserMailer.welcome_message(user, signup_confirm_url.nil? ? nil : (signup_confirm_url + "/" + user.signup_token) ).deliver end end - user.signup_token = SecureRandom.urlsafe_base64 - user.save - - if user.errors.any? - raise ActiveRecord::Rollback - else - # FIXME: - # It's not standard to require a confirmation when a user signs up with Facebook. - # We should stop asking for it. - # - # any errors here should also rollback the transaction; that's OK. If emails aren't going to be delivered, - # it's already a really bad situation; make user signup again - UserMailer.welcome_message(user, signup_confirm_url.nil? ? nil : (signup_confirm_url + "/" + user.signup_token) ).deliver - end - end - - return user - end - - # throws RecordNotFound if signup token is invalid; i.e., if it's nil, empty string, or not belonging to a user - def self.signup_confirm(signup_token) - if signup_token.nil? || signup_token.empty? - # there are plenty of confirmed users with nil signup_tokens, so we can't look on it - raise ActiveRecord::RecordNotFound - else - UserManager.active_record_transaction do |user_manager| - # throws ActiveRecord::RecordNotFound if invalid - user = User.find_by_signup_token!(signup_token) - user.signup_token = nil - user.email_confirmed = true - user.save - return user - end - end - end - - # if valid credentials are supplied for an 'active' user, returns the user - # if not authenticated, returns nil - def self.authenticate(email, password) - # we only allow users that have confirmed email to authenticate - user = User.where('email_confirmed=true').find_by_email(email) - - if user && user.authenticate(password) return user - else - return nil end - end + # throws RecordNotFound if signup token is invalid; i.e., if it's nil, empty string, or not belonging to a user + def self.signup_confirm(signup_token) + if signup_token.nil? || signup_token.empty? + # there are plenty of confirmed users with nil signup_tokens, so we can't look on it + raise ActiveRecord::RecordNotFound + else + UserManager.active_record_transaction do |user_manager| + # throws ActiveRecord::RecordNotFound if invalid + user = User.find_by_signup_token!(signup_token) + user.signup_token = nil + user.confirm_email! + user.save + return user + end + end + end + + # if valid credentials are supplied for an 'active' user, returns the user + # if not authenticated, returns nil + def self.authenticate(email, password) + # we only allow users that have confirmed email to authenticate + user = User.where('email_confirmed=true').find_by_email(email) + + if user && user.authenticate(password) + return user + else + return nil + end + end ### Elasticsearch/Tire integration ### @@ -388,5 +428,23 @@ module JamRuby def create_remember_token self.remember_token = SecureRandom.urlsafe_base64 end + + def self.validate_instruments(instruments, is_nil_ok) + if is_nil_ok && instruments.nil? + return + end + + if instruments.nil? + raise JamRuby::JamArgumentError, ValidationMessages::INSTRUMENT_MINIMUM_NOT_MET + else + if instruments.size < Limits::MIN_INSTRUMENTS_PER_MUSICIAN + raise JamRuby::JamArgumentError, ValidationMessages::INSTRUMENT_MINIMUM_NOT_MET + end + + if instruments.size > Limits::MAX_INSTRUMENTS_PER_MUSICIAN + raise JamRuby::JamArgumentError, ValidationMessages::INSTRUMENT_LIMIT_EXCEEDED + end + end + end end end diff --git a/lib/jam_ruby/models/user_favorite.rb b/lib/jam_ruby/models/user_favorite.rb index 5de3e8504..04053bb22 100644 --- a/lib/jam_ruby/models/user_favorite.rb +++ b/lib/jam_ruby/models/user_favorite.rb @@ -6,5 +6,6 @@ module JamRuby self.primary_key = 'id' belongs_to :user, :class_name => "JamRuby::User", :foreign_key => "user_id", :inverse_of => :inverse_favorites + belongs_to :recording, :class_name => "JamRuby::Recording", :foreign_key => "recording_id" end end \ No newline at end of file diff --git a/spec/factories.rb b/spec/factories.rb index 78d3d8908..d7a0e367d 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -1,18 +1,22 @@ FactoryGirl.define do factory :user, :class => JamRuby::User do sequence(:email) { |n| "person_#{n}@example.com"} + sequence(:first_name) { |n| "Person" } + sequence(:last_name) { |n| "#{n}" } password "foobar" password_confirmation "foobar" email_confirmed true + city "Apex" + state "NC" + country "USA" musician true - factory :admin do admin true end end - factory :music_session, :class => "JamRuby::MusicSession" do + factory :music_session, :class => JamRuby::MusicSession do sequence(:description) { |n| "Music Session #{n}" } fan_chat true fan_access true @@ -34,7 +38,11 @@ FactoryGirl.define do end factory :band, :class => JamRuby::Band do - + sequence(:name) { |n| "Band" } + biography "My Biography" + city "Apex" + state "NC" + country "USA" end factory :join_request, :class => JamRuby::JoinRequest do diff --git a/spec/jam_ruby/connection_manager_spec.rb b/spec/jam_ruby/connection_manager_spec.rb index 3102ff251..c4dc62935 100644 --- a/spec/jam_ruby/connection_manager_spec.rb +++ b/spec/jam_ruby/connection_manager_spec.rb @@ -12,7 +12,7 @@ describe ConnectionManager do end def create_user(first_name, last_name, email, options = {:musician => true}) - @conn.exec("INSERT INTO users (first_name, last_name, email, musician, password_digest) VALUES ($1, $2, $3, $4, $5) RETURNING id", [first_name, last_name, email, options[:musician], '1']) do |result| + @conn.exec("INSERT INTO users (first_name, last_name, email, musician, password_digest, city, state, country) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING id", [first_name, last_name, email, options[:musician], '1', 'Apex', 'NC', 'USA']) do |result| return result.getvalue(0, 0) end end diff --git a/spec/jam_ruby/models/band_search_spec.rb b/spec/jam_ruby/models/band_search_spec.rb index abbe0cd35..1c45a2045 100644 --- a/spec/jam_ruby/models/band_search_spec.rb +++ b/spec/jam_ruby/models/band_search_spec.rb @@ -2,11 +2,13 @@ require 'spec_helper' describe User do + let(:user) { FactoryGirl.create(:user) } + before(:each) do Band.delete_search_index Band.create_search_index - @band = Band.save(name: "Example Band", website: "www.bands.com", biography: "zomg we rock") + @band = Band.save(nil, "Example Band", "www.bands.com", "zomg we rock", "Apex", "NC", "USA", ["hip hop"], user.id, nil, nil) # you have to poke elasticsearch because it will batch requests internally for a second Band.search_index.refresh @@ -20,8 +22,6 @@ describe User do band_result.name.should == @band.name band_result.id.should == @band.id band_result.location.should == @band.location - band_result.logo_url.should_not be_nil - band_result.photo_url.should_not be_nil end it "should delete band" do @@ -58,7 +58,7 @@ describe User do end it "should tokenize correctly" do - @band2 = Band.save(name: "Peach pit", website: "www.bands.com", biography: "zomg we rock") + @band2 = Band.save(nil, "Peach pit", "www.bands.com", "zomg we rock", "Apex", "NC", "USA", ["hip hop"], user.id, nil, nil) Band.search_index.refresh ws = Band.search("pea") ws.results.length.should == 1 @@ -68,7 +68,7 @@ describe User do it "should not return anything with a 1 character search" do - @band2 = Band.save(name: "Peach pit", website: "www.bands.com", biography: "zomg we rock") + @band2 = Band.save(nil, "Peach pit", "www.bands.com", "zomg we rock", "Apex", "NC", "USA", ["hip hop"], user.id, nil, nil) Band.search_index.refresh ws = Band.search("pe") ws.results.length.should == 1 diff --git a/spec/jam_ruby/models/search_spec.rb b/spec/jam_ruby/models/search_spec.rb index f1655aab8..25f7bf77b 100644 --- a/spec/jam_ruby/models/search_spec.rb +++ b/spec/jam_ruby/models/search_spec.rb @@ -11,9 +11,9 @@ describe Search do def create_peachy_data - @user = FactoryGirl.create(:user, first_name: "Peach", last_name: "Pit", email: "user@example.com", musician: true) - @fan = FactoryGirl.create(:user, first_name: "Peach Peach", last_name: "Pit", email: "fan@example.com", musician: false) - @band = FactoryGirl.create(:band, name: "Peach pit", website: "www.bands.com", biography: "zomg we rock") + @user = FactoryGirl.create(:user, first_name: "Peach", last_name: "Pit", email: "user@example.com", musician: true, city: "Apex", state: "NC", country:"USA") + @fan = FactoryGirl.create(:user, first_name: "Peach Peach", last_name: "Pit", email: "fan@example.com", musician: false, city: "Apex", state: "NC", country:"USA") + @band = FactoryGirl.create(:band, name: "Peach pit", website: "www.bands.com", biography: "zomg we rock", city: "Apex", state: "NC", country:"USA") end def assert_peachy_data diff --git a/spec/jam_ruby/models/tire_search_spec.rb b/spec/jam_ruby/models/tire_search_spec.rb index c1306d081..efc42c22d 100644 --- a/spec/jam_ruby/models/tire_search_spec.rb +++ b/spec/jam_ruby/models/tire_search_spec.rb @@ -20,7 +20,9 @@ describe "tire search" do end it "full search for single user" do - @user = FactoryGirl.create(:user, first_name: "User", last_name: "One", email: "user@example.com", musician: true) + @user = FactoryGirl.create(:user, first_name: "User", last_name: "One", email: "user@example.com", musician: true, + city: "Apex", state: "NC", country: "USA") + User.search_index.refresh s = Tire.search ['test-jamruby-users', 'test-jamruby-bands'], :load => true do @@ -34,7 +36,9 @@ describe "tire search" do end it "full search for single band" do - @band = FactoryGirl.create(:band, name: "Example Band", website: "www.bands.com", biography: "zomg we rock") + @band = FactoryGirl.create(:band, name: "Example Band", website: "www.bands.com", biography: "zomg we rock", + city: "Apex", state: "NC", country: "USA") + Band.search_index.refresh s = Tire.search ['test-jamruby-users', 'test-jamruby-bands'], :load => true do @@ -48,8 +52,8 @@ describe "tire search" do end it "full search for a band & user" do - @user = FactoryGirl.create(:user, first_name: "Peach", last_name: "Foo", email: "user@example.com", musician: true) - @band = FactoryGirl.create(:band, name: "Peach pit", website: "www.bands.com", biography: "zomg we rock") + @user = FactoryGirl.create(:user, first_name: "Peach", last_name: "Foo", email: "user@example.com", musician: true, city: "Apex", state: "NC", country: "USA") + @band = FactoryGirl.create(:band, name: "Peach pit", website: "www.bands.com", biography: "zomg we rock", city: "Apex", state: "NC", country: "USA") User.search_index.refresh Band.search_index.refresh @@ -70,8 +74,8 @@ describe "tire search" do it "pagination" do - @user = FactoryGirl.create(:user, first_name: "Peach", last_name: "foo", email: "user@example.com", musician: true) - @band = FactoryGirl.create(:band, name: "Peach pit", website: "www.bands.com", biography: "zomg we rock") + @user = FactoryGirl.create(:user, first_name: "Peach", last_name: "foo", email: "user@example.com", musician: true, city: "Apex", state: "NC", country: "USA") + @band = FactoryGirl.create(:band, name: "Peach pit", website: "www.bands.com", biography: "zomg we rock", city: "Apex", state: "NC", country: "USA") User.search_index.refresh Band.search_index.refresh diff --git a/spec/jam_ruby/models/user_search_spec.rb b/spec/jam_ruby/models/user_search_spec.rb index 27c655e68..35c3e806a 100644 --- a/spec/jam_ruby/models/user_search_spec.rb +++ b/spec/jam_ruby/models/user_search_spec.rb @@ -7,7 +7,8 @@ describe User do User.create_search_index @user = FactoryGirl.create(:user, first_name: "Example", last_name: "User", email: "user@example.com", - password: "foobar", password_confirmation: "foobar", musician: true, email_confirmed: true) + password: "foobar", password_confirmation: "foobar", musician: true, email_confirmed: true, + city: "Apex", state: "NC", country: "USA") # you have to poke elasticsearch because it will batch requests internally for a second User.search_index.refresh end @@ -22,7 +23,6 @@ describe User do user_result.id.should == @user.id user_result.location.should == @user.location user_result.musician.should == true - user_result.photo_url.should_not be_nil end it "should delete user" do @@ -50,7 +50,7 @@ describe User do User.search_index.refresh ws = User.search("Example User") - ws.results.length.should == 0 + ws.results.length.should == 1 ws = User.search("Bonus") ws.results.length.should == 1 @@ -61,7 +61,8 @@ describe User do it "should tokenize correctly" do @user2 = FactoryGirl.create(:user, first_name: "peaches", last_name: "test", email: "peach@example.com", - password: "foobar", password_confirmation: "foobar", musician: true, email_confirmed: true) + password: "foobar", password_confirmation: "foobar", musician: true, email_confirmed: true, + city: "Apex", state: "NC", country: "USA") User.search_index.refresh ws = User.search("pea") ws.results.length.should == 1 @@ -69,10 +70,10 @@ describe User do user_result.id.should == @user2.id end - it "users who have signed up, but not confirmed should not show up in search index" do @user3 = FactoryGirl.create(:user, first_name: "unconfirmed", last_name: "unconfirmed", email: "unconfirmed@example.com", - password: "foobar", password_confirmation: "foobar", musician: true, email_confirmed: false) + password: "foobar", password_confirmation: "foobar", musician: true, email_confirmed: false, + city: "Apex", state: "NC", country: "USA") User.search_index.refresh ws = User.search("unconfirmed") ws.results.length.should == 0 diff --git a/spec/jam_ruby/models/user_spec.rb b/spec/jam_ruby/models/user_spec.rb index cadf83fb2..bb20bb641 100644 --- a/spec/jam_ruby/models/user_spec.rb +++ b/spec/jam_ruby/models/user_spec.rb @@ -4,7 +4,7 @@ describe User do before do @user = User.new(first_name: "Example", last_name: "User", email: "user@example.com", - password: "foobar", password_confirmation: "foobar") + password: "foobar", password_confirmation: "foobar", city: "Apex", state: "NC", country: "USA") end subject { @user }