diff --git a/ruby/lib/jam_ruby/models/band.rb b/ruby/lib/jam_ruby/models/band.rb index 5f8da60e1..58ea30e1b 100644 --- a/ruby/lib/jam_ruby/models/band.rb +++ b/ruby/lib/jam_ruby/models/band.rb @@ -26,30 +26,30 @@ module JamRuby before_save :check_website_url # musicians - has_many :band_musicians, :class_name => "JamRuby::BandMusician" + has_many :band_musicians, :class_name => "JamRuby::BandMusician", dependent: :destroy has_many :users, :through => :band_musicians, :class_name => "JamRuby::User" # genres - has_many :band_genres, class_name: "JamRuby::BandGenre" + has_many :band_genres, class_name: "JamRuby::BandGenre", dependent: :destroy has_many :genres, class_name: "JamRuby::Genre", :through => :band_genres # recordings - has_many :recordings, :class_name => "JamRuby::Recording", :foreign_key => "band_id" + has_many :recordings, :class_name => "JamRuby::Recording", :foreign_key => "band_id", dependent: :destroy # self.id = likable_id in likes table - has_many :likers, :as => :likable, :class_name => "JamRuby::Like", :dependent => :destroy + has_many :likers, :as => :likable, :class_name => "JamRuby::Like", :dependent => :destroy, dependent: :destroy # self.id = followable_id in follows table - has_many :followers, :as => :followable, :class_name => "JamRuby::Follow", :dependent => :destroy + has_many :followers, :as => :followable, :class_name => "JamRuby::Follow", :dependent => :destroy, dependent: :destroy # invitations - has_many :invitations, :inverse_of => :band, :class_name => "JamRuby::BandInvitation", :foreign_key => "band_id" + has_many :invitations, :inverse_of => :band, :class_name => "JamRuby::BandInvitation", :foreign_key => "band_id", dependent: :destroy # music_sessions - has_many :music_sessions, :class_name => "JamRuby::MusicSession", foreign_key: :band_id, :inverse_of => :band + has_many :music_sessions, :class_name => "JamRuby::MusicSession", foreign_key: :band_id, :inverse_of => :band, dependent: :destroy # events - has_many :event_sessions, :class_name => "JamRuby::EventSession" + has_many :event_sessions, :class_name => "JamRuby::EventSession", dependent: :destroy include Geokit::ActsAsMappable::Glue unless defined?(acts_as_mappable) acts_as_mappable @@ -114,11 +114,16 @@ module JamRuby end def self.musician_index(band_id) - @musicians = User.joins(:band_musicians).where(:bands_musicians => {:band_id => "#{band_id}"}) + @musicians = User + .select("users.*, bands_musicians.admin AS band_admin") + .joins(:band_musicians) + .where(:bands_musicians => {:band_id => "#{band_id}"}) end def self.pending_musicians(band_id) - @musicians = User.joins(:received_band_invitations) + @musicians = User + .select("users.*, band_invitations.id AS invitation_id") + .joins(:received_band_invitations) .where(:band_invitations => {:band_id => "#{band_id}"}) .where(:band_invitations => {:accepted => nil}) end @@ -285,6 +290,12 @@ module JamRuby Band.connection.execute("UPDATE bands SET lat = geo.latitude, lng = geo.longitude FROM geoiplocations#{table_suffix} as geo WHERE bands.city = geo.city AND bands.state = geo.region AND bands.country = geo.countrycode") end + def self.is_member?(band_id, user_id) + BandMusician.where(band_id: band_id, user_id: user_id) + .limit(1) + .present? + end + private def require_at_least_one_genre diff --git a/ruby/lib/jam_ruby/models/band_invitation.rb b/ruby/lib/jam_ruby/models/band_invitation.rb index edfdbd998..35b1973d1 100644 --- a/ruby/lib/jam_ruby/models/band_invitation.rb +++ b/ruby/lib/jam_ruby/models/band_invitation.rb @@ -7,11 +7,13 @@ module JamRuby BAND_INVITATION_FAN_RECIPIENT_ERROR = "A Band invitation can only be sent to a Musician." + validates_uniqueness_of :user_id, scope: :band_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) + def self.save(id, band_id, user_id, creator_id, accepted, resend=false) band_invitation = BandInvitation.new() @@ -39,8 +41,17 @@ module JamRuby # only the accepted flag can be updated after initial creation else band_invitation = BandInvitation.find(id) - band_invitation.accepted = accepted - band_invitation.save + if resend + Notification.send_band_invitation( + band_invitation.band, + band_invitation, + band_invitation.sender, + band_invitation.receiver + ) + else + band_invitation.accepted = accepted + band_invitation.save + end end # accept logic: @@ -69,4 +80,4 @@ module JamRuby band_invitation end end -end \ No newline at end of file +end diff --git a/web/app/assets/javascripts/bandProfile.js b/web/app/assets/javascripts/bandProfile.js index dff8c01fd..c140d2ea2 100644 --- a/web/app/assets/javascripts/bandProfile.js +++ b/web/app/assets/javascripts/bandProfile.js @@ -8,6 +8,7 @@ var rest = context.JK.Rest(); var bandId; var isMember = false; + var isAdmin = false; var band = {}; var instrument_logo_map = context.JK.getInstrumentIconMap24(); @@ -146,7 +147,8 @@ $("#btn-edit-band-profile").show(); $("#btn-edit-band-info").show(); $("#btn-edit-band-members").show(); - $("#btn-edit-band-delete").show(); + if (isAdmin) + $("#btn-edit-band-delete").show(); } else { $("#btn-follow-band").show(); @@ -369,6 +371,8 @@ var memberHtml = context.JK.fillTemplate(template, { userId: musician.id, band_admin: bandAdmin, + is_pending: isPending, + invitation_id: isPending ? musician.invitation_id : '', profile_url: "/client#/profile/" + musician.id, avatar_url: context.JK.resolveAvatarUrl(musician.photo_url), name: musician.name, @@ -391,11 +395,25 @@ // var friend = isFriend(musician.id); // configureMemberFriendButton(friend, musician.id); }); + if (isPending) { + $('div[pending-member=true] .btn-reinvite-member').each(function() { + var btn = $(this); + btn.show(); + btn.unbind('click'); + btn.click(function() { + var inviteid = $(this).closest('.band-profile-members').attr('invitation-id'); + rest.resendBandInvitation(bandId, inviteid) + .done(function (response) { + app.notifyAlert('Band Invitation', 'Your invitation has been re-sent'); + }).fail(app.ajaxError); + }); + }); + } } function configureRemoveMemberButton(userId, isPending, bandAdmin) { var $divMember = $('div[user-id=' + userId + ']', '#band-profile-members'); - var $btnRemoveMember = $divMember.find('#btn-remove-member'); + var $btnRemoveMember = $divMember.find('.btn-remove-member'); if (isMember && !isPending && !bandAdmin) { $btnRemoveMember.show(); $btnRemoveMember.unbind("click"); @@ -411,6 +429,13 @@ rest.removeBandMember(bandId, userId) .done(function() { $divMember.remove(); + if (userId == context.JK.currentUserId) { + $('#btn-edit-band-profile').hide(); + $('#btn-edit-band-info').hide(); + $('#btn-edit-band-members').hide(); + $('.btn-remove-member').each(function(idx) { $(this).hide(); }); + $('.btn-reinvite-member').each(function(idx) { $(this).hide(); }); + } }) .fail(app.ajaxError); }); @@ -435,10 +460,13 @@ error: app.ajaxError }) .done(function(response) { - isMember = false; + isAdmin = isMember = false; $.each(response, function(index, val) { if (val.id === context.JK.currentUserId) { isMember = true; + if (val.band_admin) { + isAdmin = true; + } } }); }) @@ -464,6 +492,23 @@ context.location = "/client#/band/setup/" + bandId + '/step2'; return false; }); + $("#btn-edit-band-delete").unbind('click').click(function() { + var confirmDialog = new context.JK.ConfirmDialog(app, + "DELETE", + "Are you sure you want to delete this band? This is a permanent action which cannot be undone.", + "Delete Band", + function() { + app.layout.closeDialog('confirm'); + rest.deleteBand(bandId) + .done(function() { + context.location = "/client#/profile/"+context.JK.currentUserId; + }) + .fail(app.ajaxError); + }); + confirmDialog.initialize(); + context.JK.app.layout.showDialog('confirm'); + return false; + }); } function initialize() { diff --git a/web/app/assets/javascripts/band_setup.js b/web/app/assets/javascripts/band_setup.js index e3a7c0436..44324bc78 100644 --- a/web/app/assets/javascripts/band_setup.js +++ b/web/app/assets/javascripts/band_setup.js @@ -127,6 +127,10 @@ return band; } + function showProfile(band_id) { + context.location = "/client#/bandProfile/" + band_id; + } + function saveBand() { if (isSaving) return; isSaving = true; @@ -137,9 +141,12 @@ rest.createBand(band) .done(function (response) { isSaving = false; - createBandInvitations(response.id, function () { - context.location = "/client#/bandProfile/" + response.id; - }); + if (0 < $('#selected-friends-band .invitation').length) { + createBandInvitations(response.id, function () { + showProfile(response.id); + }); + } else + showProfile(response.id); }) .fail(function (jqXHR) { isSaving = false; @@ -154,7 +161,7 @@ .done(function (response) { isSaving = false; createBandInvitations(band.id, function () { - context.location = "/client#/bandProfile/" + band.id; + showProfile(band.id); }); }).fail(function (jqXHR) { isSaving = false; @@ -172,10 +179,13 @@ }); } else if (step2) { isSaving = false; - createBandInvitations(bandId, function () { - app.notifyAlert('Band Members', 'Your invitations have been sent'); - context.location = "/client#/bandProfile/" + bandId; - }); + if (0 < $('#selected-friends-band .invitation').length) { + createBandInvitations(bandId, function () { + app.notifyAlert('Band Members', 'Your invitations have been sent'); + showProfile(bandId); + }); + } else + showProfile(bandId); } } } @@ -488,8 +498,7 @@ $("#band-setup-step-1").show(); $("#band-setup-step-2").hide(); } else { - resetForm(); - window.history.go(-1); + showProfile(bandId); return false; } }); diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index ad1993899..368d6a72f 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -350,6 +350,17 @@ return deferred; } + function deleteBand(bandId) { + var url = "/api/bands/" + bandId; + return $.ajax({ + type: "DELETE", + dataType: "json", + url: url, + contentType: 'application/json', + processData:false + }); + } + function updateBand(band) { return $.ajax({ type: "POST", @@ -396,6 +407,17 @@ return deferred; } + function resendBandInvitation(bandId, invitationId) { + return $.ajax({ + type: "POST", + dataType: "json", + url: '/api/bands/' + bandId + "/invitations/" + invitationId, + contentType: 'application/json', + processData: false, + data: JSON.stringify({"resend": true}) + }) + } + function removeBandMember(bandId, userId) { var url = "/api/bands/" + bandId + "/musicians/" + userId; return $.ajax({ @@ -1456,6 +1478,7 @@ this.updateBand = updateBand; this.updateBandPhoto = updateBandPhoto; this.deleteBandPhoto = deleteBandPhoto; + this.deleteBand = deleteBand; this.getBandPhotoFilepickerPolicy = getBandPhotoFilepickerPolicy; this.getBand = getBand; this.validateBand = validateBand; @@ -1486,6 +1509,7 @@ this.updateBillingInfo = updateBillingInfo; this.placeOrder = placeOrder; this.searchMusicians = searchMusicians; + this.resendBandInvitation = resendBandInvitation; return this; }; diff --git a/web/app/controllers/api_bands_controller.rb b/web/app/controllers/api_bands_controller.rb index 6f518fa4d..cd800aa61 100644 --- a/web/app/controllers/api_bands_controller.rb +++ b/web/app/controllers/api_bands_controller.rb @@ -5,6 +5,7 @@ class ApiBandsController < ApiController :recording_create, :recording_update, :recording_destroy, :invitation_index, :invitation_show, :invitation_create, :invitation_destroy, :update_photo, :delete_photo, :generate_filepicker_policy] + before_filter :auth_band_admin, :only => [:delete] respond_to :json @@ -17,6 +18,11 @@ class ApiBandsController < ApiController respond_with_model(@band) end + def delete + @band.try(:destroy) + respond_with @band, responder => ApiResponder + end + def create @band = Band.save(current_user, params) @@ -148,21 +154,32 @@ class ApiBandsController < ApiController end def invitation_create - @invitation = BandInvitation.save(nil, - params[:id], - params[:user_id], - current_user.id, - params[:accepted]) - - respond_with @invitation, responder: ApiResponder, :status => 201, :location => api_band_invitation_detail_url(@band, @invitation) + unless Band.is_member?(params[:id], params[:user_id]) + @invitation = BandInvitation.save(nil, + params[:id], + params[:user_id], + current_user.id, + params[:accepted]) + end + respond_with @invitation, responder: ApiResponder, :status => 201 + # respond_with @invitation, responder: ApiResponder, :status => 201, :location => api_band_invitation_detail_url(@band, @invitation) end def invitation_update - @invitation = BandInvitation.save(params[:invitation_id], - nil, - nil, - nil, - params[:accepted]) + if params[:resend] + @invitation = BandInvitation.save(params[:invitation_id], + nil, + nil, + nil, + false, + true) + else + @invitation = BandInvitation.save(params[:invitation_id], + nil, + nil, + nil, + params[:accepted]) + end end def invitation_destroy @@ -236,4 +253,11 @@ class ApiBandsController < ApiController raise PermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR end end + def auth_band_admin + uid = current_user.id + @band = Band.find(params[:id]) + unless @band.band_musicians.detect { |bm| bm.user_id == uid && bm.admin? } + raise PermissionError, ValidationMessages::PERMISSION_VALIDATION_ERROR + end + end end diff --git a/web/app/views/api_bands/musician_index.rabl b/web/app/views/api_bands/musician_index.rabl index cfb95ab15..2c6cef6b2 100644 --- a/web/app/views/api_bands/musician_index.rabl +++ b/web/app/views/api_bands/musician_index.rabl @@ -3,7 +3,11 @@ collection @musicians attributes :id, :first_name, :last_name, :name, :city, :state, :country, :location, :online, :photo_url, :musician, :gender, :birth_date, :internet_service_provider, :friend_count, :liker_count, :like_count, :follower_count, :following_count, :recording_count, :session_count, :biography node :band_admin do |musician| - 't' == musician.band_admin ? true : false + musician.respond_to?(:band_admin) && 't' == musician.band_admin ? true : false +end + +node :invitation_id do |musician| + musician.respond_to?(:invitation_id) ? musician.invitation_id : nil end node :instruments do |musician| diff --git a/web/app/views/clients/_bandProfile.html.erb b/web/app/views/clients/_bandProfile.html.erb index 9441fefeb..3f58378ee 100644 --- a/web/app/views/clients/_bandProfile.html.erb +++ b/web/app/views/clients/_bandProfile.html.erb @@ -89,7 +89,7 @@