jam-cloud/lib/jam_ruby/models/recording.rb

302 lines
9.5 KiB
Ruby

module JamRuby
class Recording < ActiveRecord::Base
self.primary_key = 'id'
has_and_belongs_to_many :users, :class_name => "JamRuby::User"
belongs_to :owner, :class_name => "JamRuby::User", :inverse_of => :owned_recordings
belongs_to :band, :class_name => "JamRuby::Band", :inverse_of => :recordings
belongs_to :music_session, :class_name => "JamRuby::MusicSession", :inverse_of => :recording
has_many :recorded_tracks, :class_name => "JamRuby::RecordedTrack", :foreign_key => :recording_id
# genres
has_and_belongs_to_many :genres, :class_name => "JamRuby::Genre", :join_table => "recordings_genres"
# favorites
has_many :favorites, :class_name => "JamRuby::UserFavorite", :foreign_key => "recording_id"
has_many :inverse_favorites, :through => :favorites, :source => :recording, :class_name => "JamRuby::Recording"
validates :name, length: { maximum: 100 }
validates :description, length: { maximum: 200 }
validates :genres, length: { maximum: 3 }
def favorite_count
return self.favorites.size
end
def self.user_recordings(user_id)
query = Recording
.joins(
%Q{
INNER JOIN
recordings_users
ON
recordings_users.recording_id = recordings.id
}
)
.order(
%Q{
recordings.created_at DESC
}
)
.where(
%Q{
recordings_users.user_id = '#{user_id}'
}
)
query
end
# Start recording a session.
def self.start(music_session_id, owner)
recording = nil
# Use a transaction and lock to avoid races.
ActiveRecord::Base.transaction do
music_session = MusicSession.find(music_session_id, :lock => true)
if music_session.nil?
raise PermissionError, "the session has ended"
end
unless music_session.recording.nil?
raise PermissionError, "the session is already being recorded"
end
recording = Recording.new
recording.music_session = music_session
recording.owner = owner
recording.is_public = false
recording.is_downloadable = false
music_session.connections.each do |connection|
recording.users << connection.user
connection.tracks.each do |track|
RecordedTrack.create_from_track(track, recording)
end
end
music_session.genres.each do |genre|
recording.genres << genre
end
# Note that I believe this can be nil.
recording.band = music_session.band
recording.save
music_session.recording = recording
music_session.save
end
# FIXME:
# NEED TO SEND NOTIFICATION TO ALL USERS IN THE SESSION THAT RECORDING HAS STARTED HERE.
# I'LL STUB IT A BIT. NOTE THAT I REDO THE FIND HERE BECAUSE I DON'T WANT TO SEND THESE
# NOTIFICATIONS WHILE THE DB ROW IS LOCKED
music_session = MusicSession.find(music_session_id)
music_session.connections.each do |connection|
# connection.notify_recording_has_started
end
recording
end
# Stop recording a session
# FIXME: What to do about recordings which are started and then stopped but never get any metadata (not even a name)?
# I'm guessing they should be deleted eventually.
def stop
# Use a transaction and lock to avoid races.
ActiveRecord::Base.transaction do
music_session = MusicSession.find(self.music_session_id, :lock => true)
if music_session.nil?
raise PermissionError, "the session has ended"
end
unless music_session.recording
raise PermissionError, "the session is not currently being recorded"
end
music_session.recording = nil
music_session.save
end
end
# Update the metadata for the recording.
def update_fields(params)
unless self.music_session.nil?
raise PermissionError, "recording data cannot be changed while it is being recorded"
end
if params[:name].nil?
raise PermissionError, "recording must have a name" if self.name.nil?
end
self.name = params[:name] unless params[:name].nil?
self.description = params[:description] unless params[:description].nil?
genres = params[:genres]
unless genres.nil?
validate_genres(genres)
self.genres = []
genres.each do |genre_id|
g = Genre.find(genre_id)
self.genres << g
end
end
self.is_public = params[:is_public] unless params[:is_public].nil?
self.is_downloadable = params[:is_downloadable] unless params[:is_downloadable].nil?
save
end
# Find out if all the tracks for this recording have been uploaded
def uploaded?
self.recorded_tracks.each do |recorded_track|
return false unless recorded_track.fully_uploaded
end
return true
end
def self.search(query, options = { :limit => 10 })
# only issue search if at least 2 characters are specified
if query.nil? || query.length < 2
return []
end
# create 'anded' statement
query = Search.create_tsquery(query)
if query.nil? || query.length == 0
return []
end
return Recording.where("description_tsv @@ to_tsquery('jamenglish', ?)", query).limit(options[:limit])
end
def self.save(id, is_public, description, genres, updater_id, owner_id, is_band)
return nil
# Spec: https://jamkazam.atlassian.net/wiki/display/PS/Product+Specification+-+Studio
# This is seriously wrong. A recording needs to be created from inside a session. I'm not sure who owns
# the recording, but I do know that it's affiliated with the session and then should be able to get the band id
# and probably all this other stuff (genre, etc) from that. I need to read the recording spec in more detail
# to figure that out. I'll read it on bart.
#
# The studio spec is the key here. A couple notes:
# * Multiple musicians are all associated with a recording -- everyone who is in the music session when the recording starts
# * Associating a band with the recording is optional
# * The recording needs to be associated with a music_session for sure. Probably also a set of tracks (NOT musicians). Then, on
# recording completion is when you have the track -> saved_track (rename this to recorded_track) transition.
# * The metadata in general is filled in *after* the recording ends. This is important because it means the save method below
# is sort of jacked.
=begin
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?
validate_genres(genres, false)
recording = Recording.new()
recording.creator_id = updater_id
else
validate_genres(genres, true)
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
# genres
unless genres.nil?
ActiveRecord::Base.transaction do
# delete all genres for this recording first
unless recording.id.nil? || recording.id.length == 0
recording.genres.delete_all
end
# loop through each genre in the array and save to the db
genres.each do |genre_id|
g = Genre.find(genre_id)
recording.genres << g
end
end
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
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
def validate_genres(genres)
if genres.length < Limits::MIN_GENRES_PER_RECORDING
raise JamRuby::JamArgumentError, ValidationMessages::GENRE_MINIMUM_NOT_MET
end
if genres.length > Limits::MAX_GENRES_PER_RECORDING
raise JamRuby::JamArgumentError, ValidationMessages::GENRE_LIMIT_EXCEEDED
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