diff --git a/db/manifest b/db/manifest index 9f19d8fe7..bc10f39b4 100755 --- a/db/manifest +++ b/db/manifest @@ -77,4 +77,5 @@ whats_next.sql add_user_bio.sql users_geocoding.sql recordings_public_launch.sql -notification_band_invite.sql \ No newline at end of file +notification_band_invite.sql +band_photo_filepicker.sql \ No newline at end of file diff --git a/db/up/band_photo_filepicker.sql b/db/up/band_photo_filepicker.sql new file mode 100644 index 000000000..181fc1469 --- /dev/null +++ b/db/up/band_photo_filepicker.sql @@ -0,0 +1,4 @@ +ALTER TABLE bands ADD COLUMN original_fpfile_photo VARCHAR(8000) DEFAULT NULL; +ALTER TABLE bands ADD COLUMN cropped_fpfile_photo VARCHAR(8000) DEFAULT NULL; +ALTER TABLE bands ADD COLUMN cropped_s3_path_photo VARCHAR(512) DEFAULT NULL; +ALTER TABLE bands ADD COLUMN crop_selection_photo VARCHAR(256) DEFAULT NULL; \ No newline at end of file diff --git a/ruby/lib/jam_ruby/models/band.rb b/ruby/lib/jam_ruby/models/band.rb index 5f47cdb9d..640f6c2a0 100644 --- a/ruby/lib/jam_ruby/models/band.rb +++ b/ruby/lib/jam_ruby/models/band.rb @@ -1,10 +1,16 @@ module JamRuby class Band < ActiveRecord::Base - attr_accessible :name, :website, :biography, :city, :state, :country + attr_accessible :name, :website, :biography, :city, :state, + :country, :original_fpfile_photo, :cropped_fpfile_photo, + :cropped_s3_path_photo, :crop_selection_photo, :photo_url + + attr_accessor :updating_photo self.primary_key = 'id' + before_save :stringify_photo_info , :if => :updating_photo + validate :validate_photo_info validates :biography, no_profanity: true # musicians @@ -57,6 +63,14 @@ module JamRuby loc end + def validate_photo_info + if updating_photo + # we want to mak sure that original_fpfile and cropped_fpfile seems like real fpfile info objects (i.e, json objects from filepicker.io) + errors.add(:original_fpfile_photo, ValidationMessages::INVALID_FPFILE) if self.original_fpfile_photo.nil? || self.original_fpfile_photo["key"].nil? || self.original_fpfile_photo["url"].nil? + errors.add(:cropped_fpfile_photo, ValidationMessages::INVALID_FPFILE) if self.cropped_fpfile_photo.nil? || self.cropped_fpfile_photo["key"].nil? || self.cropped_fpfile_photo["url"].nil? + end + end + def add_member(user_id, admin) BandMusician.create(:band_id => self.id, :user_id => user_id, :admin => admin) end @@ -187,6 +201,40 @@ module JamRuby return band end + def update_photo(original_fpfile, cropped_fpfile, crop_selection, aws_bucket) + self.updating_photo = true + + cropped_s3_path = cropped_fpfile["key"] + + return self.update_attributes( + :original_fpfile_photo => original_fpfile, + :cropped_fpfile_photo => cropped_fpfile, + :cropped_s3_path_photo => cropped_s3_path, + :crop_selection_photo => crop_selection, + :photo_url => S3Util.url(aws_bucket, cropped_s3_path, :secure => false) + ) + end + + def delete_photo(aws_bucket) + + Band.transaction do + + unless self.cropped_s3_path.nil? + S3Util.delete(aws_bucket, File.dirname(self.cropped_s3_path) + '/cropped.jpg') + S3Util.delete(aws_bucket, self.cropped_s3_path) + end + + return self.update_attributes( + :original_fpfile_photo => nil, + :cropped_fpfile_photo => nil, + :cropped_s3_path_photo => nil, + :crop_selection_photo => nil, + :photo_url => nil + ) + end + + end + private def self.validate_genres(genres, is_nil_ok) if is_nil_ok && genres.nil? @@ -205,5 +253,15 @@ module JamRuby end end end + + def stringify_photo_info + # fpfile comes in as a hash, which is a easy-to-use and validate form. However, we store it as a VARCHAR, + # so we need t oconvert it to JSON before storing it (otherwise it gets serialized as a ruby object) + # later, when serving this data out to the REST API, we currently just leave it as a string and make a JSON capable + # client parse it, because it's very rare when it's needed at all + self.original_fpfile_photo = original_fpfile_photo.to_json if !original_fpfile_photo.nil? + self.cropped_fpfile_photo = cropped_fpfile_photo.to_json if !cropped_fpfile_photo.nil? + self.crop_selection_photo = crop_selection_photo.to_json if !crop_selection_photo.nil? + end end end diff --git a/web/app/assets/javascripts/accounts_profile_avatar.js b/web/app/assets/javascripts/accounts_profile_avatar.js index 48bbfc20d..81336953e 100644 --- a/web/app/assets/javascripts/accounts_profile_avatar.js +++ b/web/app/assets/javascripts/accounts_profile_avatar.js @@ -7,7 +7,6 @@ var self = this; var logger = context.JK.logger; var rest = context.JK.Rest(); - var userId; var user = {}; var tmpUploadPath = null; var userDetail = null; @@ -18,7 +17,6 @@ var userDropdown; function beforeShow(data) { - userId = data.id; } @@ -150,7 +148,7 @@ var avatar = $('img.preview_profile_avatar', avatarSpace); var spinner = $('
') - if(avatar.length == 0) { + if(avatar.length === 0) { avatarSpace.prepend(spinner); } else { diff --git a/web/app/assets/javascripts/band_setup.js b/web/app/assets/javascripts/band_setup.js index 3d51a93db..5752a35e4 100644 --- a/web/app/assets/javascripts/band_setup.js +++ b/web/app/assets/javascripts/band_setup.js @@ -229,6 +229,7 @@ userNames = []; userIds = []; userPhotoUrls = []; + //bandId = "1158c8b6-4c92-47dc-82bf-1e390c4f9b2c"; bandId = $("#hdn-band-id").val(); resetForm(); } @@ -259,6 +260,9 @@ $("#band-setup-title").html("set up band"); $("#btn-band-setup-save").html("CREATE BAND"); + + $("#band-change-photo").unbind('click'); + $("#band-change-photo").html('Set up band and then add photo.'); } } @@ -268,10 +272,14 @@ $("#band-website").val(band.website); $("#band-biography").val(band.biography); + if (band.photo_url) { + $("#band-avatar").attr('src', band.photo_url); + } + loadGenres(band.genres); loadCountries(band.country, function() { - loadRegions(band.region, function() { + loadRegions(band.state, function() { loadCities(band.city); }); }); @@ -492,6 +500,13 @@ return false; }); + $('#band-change-photo').click(function(evt) { + evt.stopPropagation(); + $("#hdn-band-id").val(bandId); + context.location = '#/band/setup/photo'; + return false; + }); + $('div[layout-id="band/setup"] .btn-email-invitation').click(function() { invitationDialog.showEmailDialog(); }); diff --git a/web/app/assets/javascripts/band_setup_photo.js b/web/app/assets/javascripts/band_setup_photo.js new file mode 100644 index 000000000..f5775cee5 --- /dev/null +++ b/web/app/assets/javascripts/band_setup_photo.js @@ -0,0 +1,431 @@ +(function(context,$) { + + "use strict"; + + context.JK = context.JK || {}; + context.JK.BandSetupPhotoScreen = function(app) { + var self = this; + var logger = context.JK.logger; + var rest = context.JK.Rest(); + var bandId; + var band = {}; + var tmpUploadPath = null; + var bandDetail = null; + var bandPhoto; + var selection = null; + var targetCropSize = 88; + var updatingBandPhoto = false; + + function beforeShow(data) { + bandId = $("#hdn-band-id").val(); + logger.debug("bandId=" + bandId); + if (!bandId) { + context.location = '#/home'; + } + } + + function afterShow(data) { + resetForm(); + renderBandPhotoScreen() + } + + function resetForm() { + // remove all display errors + $('#band-setup-photo-content-scroller form .error-text').remove() + $('#band-setup-photo-content-scroller form .error').removeClass("error") + } + + function populateBandPhoto(bandDetail) { + self.bandDetail = bandDetail; + rest.getBandPhotoFilepickerPolicy({ id:bandId }) + .done(function(filepicker_policy) { + var template= context.JK.fillTemplate($('#template-band-setup-photo').html(), { + "fp_apikey" : gon.fp_apikey, + "data-fp-store-path" : createStorePath(bandDetail) + createOriginalFilename(bandDetail), + "fp_policy" : filepicker_policy.policy, + "fp_signature" : filepicker_policy.signature + }); + $('#band-setup-photo-content-scroller').html(template); + + + var currentFpfile = determineCurrentFpfile(); + var currentCropSelection = determineCurrentSelection(bandDetail); + renderBandPhoto(currentFpfile, currentCropSelection ? JSON.parse(currentCropSelection) : null); + }) + .error(app.ajaxError); + + } + + // events for main screen + function events() { + // wire up main panel clicks + $('#band-setup-photo-content-scroller').on('click', '#band-setup-photo-upload', function(evt) { evt.stopPropagation(); handleFilePick(); return false; } ); + $('#band-setup-photo-content-scroller').on('click', '#band-setup-photo-delete', function(evt) { evt.stopPropagation(); handleDeleteBandPhoto(); return false; } ); + $('#band-setup-photo-content-scroller').on('click', '#band-setup-photo-cancel', function(evt) { evt.stopPropagation(); navToEditProfile(); return false; } ); + $('#band-setup-photo-content-scroller').on('click', '#band-setup-photo-submit', function(evt) { evt.stopPropagation(); handleUpdateBandPhoto(); return false; } ); + //$('#band-setup-photo-content-scroller').on('change', 'input[type=filepicker-dragdrop]', function(evt) { evt.stopPropagation(); afterImageUpload(evt.originalEvent.fpfile); return false; } ); + } + + function handleDeleteBandPhoto() { + + if(self.updatingBandPhoto) { + // protect against concurrent update attempts + return; + } + + self.updatingBandPhoto = true; + renderBandPhotoSpinner(); + + rest.deleteBandPhoto({ id: bandId }) + .done(function() { + removeBandPhotoSpinner({ delete:true }); + deleteBandPhotoSuccess(arguments); + selection = null; + }) + .fail(function() { + app.ajaxError(arguments); + $.cookie('original_fpfile_band_photo', null); + self.updatingBandPhoto = false; + }) + .always(function() { + + }) + } + + function deleteBandPhotoSuccess(response) { + + renderBandPhoto(null, null); + + rest.getBand(bandId) + .done(function(bandDetail) { + self.bandDetail = bandDetail; + }) + .error(app.ajaxError) + .always(function() { + self.updatingBandPhoto = false; + }) + } + + function handleFilePick() { + rest.getBandPhotoFilepickerPolicy({ id: bandId }) + .done(function(filepickerPolicy) { + renderBandPhotoSpinner(); + logger.debug("rendered spinner"); + filepicker.setKey(gon.fp_apikey); + filepicker.pickAndStore({ + mimetype: 'image/*', + maxSize: 10000*1024, + policy: filepickerPolicy.policy, + signature: filepickerPolicy.signature + }, + { path: createStorePath(self.bandDetail), access: 'public' }, + function(fpfiles) { + removeBandPhotoSpinner(); + afterImageUpload(fpfiles[0]); + }, function(fperror) { + removeBandPhotoSpinner(); + + if(fperror.code != 101) { // 101 just means the user closed the dialog + alert("unable to upload file: " + JSON.stringify(fperror)) + } + }) + }) + .fail(app.ajaxError); + + } + function renderBandPhotoScreen() { + + rest.getBand(bandId) + .done(populateBandPhoto) + .error(app.ajaxError) + } + + function navToEditProfile() { + resetForm(); + $("#hdn-band-id").val(bandId); + context.location = '#/band/setup'; + } + + function renderBandPhotoSpinner() { + var bandPhotoSpace = $('#band-setup-photo-content-scroller .band-setup-photo .avatar-space'); + // if there is already an image tag, we only obscure it. + + var bandPhoto = $('img.preview_profile_avatar', bandPhotoSpace); + + var spinner = $('') + if(bandPhoto.length === 0) { + bandPhotoSpace.prepend(spinner); + } + else { + // in this case, just style the spinner to obscure using opacity, and center it + var jcropHolder = $('.jcrop-holder', bandPhotoSpace); + spinner.width(jcropHolder.width()); + spinner.height(jcropHolder.height()); + spinner.addClass('op50'); + var jcrop = bandPhoto.data('Jcrop'); + if(jcrop) { + jcrop.disable(); + } + bandPhotoSpace.append(spinner); + } + } + + function removeBandPhotoSpinner(options) { + var bandPhotoSpace = $('#band-setup-photo-content-scroller .band-setup-photo .avatar-space'); + + if(options && options.delete) { + bandPhotoSpace.children().remove(); + } + + var spinner = $('.spinner-large', bandPhotoSpace); + spinner.remove(); + var bandPhoto = $('img.preview_profile_avatar', bandPhotoSpace); + var jcrop = bandPhoto.data('Jcrop') + if(jcrop) { + jcrop.enable(); + } + } + + function renderBandPhoto(fpfile, storedSelection) { + + // clear out + var bandPhotoSpace = $('#band-setup-photo-content-scroller .band-setup-photo .avatar-space'); + + if(!fpfile) { + renderNoBandPhoto(bandPhotoSpace); + } + else { + rest.getBandPhotoFilepickerPolicy({handle: fpfile.url, id: bandId}) + .done(function(filepickerPolicy) { + bandPhotoSpace.children().remove(); + renderBandPhotoSpinner(); + + var photo_url = fpfile.url + '?signature=' + filepickerPolicy.signature + '&policy=' + filepickerPolicy.policy; + bandPhoto = new Image(); + $(bandPhoto) + .load(function(e) { + removeBandPhotoSpinner(); + + bandPhoto = $(this); + bandPhotoSpace.append(bandPhoto); + var width = bandPhoto.naturalWidth(); + var height = bandPhoto.naturalHeight(); + + if(storedSelection) { + var left = storedSelection.x; + var right = storedSelection.x2; + var top = storedSelection.y; + var bottom = storedSelection.y2; + } + else { + if(width < height) { + var left = width * .25; + var right = width * .75; + var top = (height / 2) - (width / 4); + var bottom = (height / 2) + (width / 4); + } + else { + var top = height * .25; + var bottom = height * .75; + var left = (width / 2) - (height / 4); + var right = (width / 2) + (height / 4); + } + } + + // jcrop only works well with px values (not percentages) + // so we get container, and work out a decent % ourselves + var container = $('#band-setup-photo-content-scroller'); + + bandPhoto.Jcrop({ + aspectRatio: 1, + boxWidth: container.width() * .75, + boxHeight: container.height() * .75, + // minSelect: [targetCropSize, targetCropSize], unnecessary with scaling involved + setSelect: [ left, top, right, bottom ], + trueSize: [width, height], + onRelease: onSelectRelease, + onSelect: onSelect, + onChange: onChange + }); + }) + .error(function() { + // default to no avatar look of UI + renderNoBandPhoto(bandPhotoSpace); + }) + .attr('src', photo_url) + .attr('alt', 'profile avatar') + .addClass('preview_profile_avatar'); + }) + .fail(app.ajaxError); + } + } + + function afterImageUpload(fpfile) { + $.cookie('original_fpfile_band_photo', JSON.stringify(fpfile)); + renderBandPhoto(fpfile, null); + } + + function renderNoBandPhoto(bandPhotoSpace) { + // no photo found for band + + removeBandPhotoSpinner(); + + var noAvatarSpace = $(''); + noAvatarSpace.addClass('no-avatar-space'); + noAvatarSpace.text('Please upload a photo'); + bandPhotoSpace.append(noAvatarSpace); + } + + function handleUpdateBandPhoto(event) { + + if(self.updatingBandPhoto) { + // protect against concurrent update attempts + return; + } + + if(selection) { + var currentSelection = selection; + self.updatingBandPhoto = true; + renderBandPhotoSpinner(); + + console.log("Converting..."); + + // we convert two times; first we crop to the selected region, + // then we scale to 88x88 (targetCropSize X targetCropSize), which is the largest size we use throughout the site. + var fpfile = determineCurrentFpfile(); + rest.getBandPhotoFilepickerPolicy({ handle: fpfile.url, convert: true, id: bandId }) + .done(function(filepickerPolicy) { + filepicker.setKey(gon.fp_apikey); + filepicker.convert(fpfile, { + crop: [ + Math.round(currentSelection.x), + Math.round(currentSelection.y), + Math.round(currentSelection.w), + Math.round(currentSelection.w)], + fit: 'crop', + format: 'jpg', + quality: 90, + policy: filepickerPolicy.policy, + signature: filepickerPolicy.signature + }, { path: createStorePath(self.bandDetail) + 'cropped-' + new Date().getTime() + '.jpg', access: 'public' }, + function(cropped) { + logger.debug("converting cropped"); + rest.getBandPhotoFilepickerPolicy({handle: cropped.url, convert: true, id: bandId}) + .done(function(filepickerPolicy) { + filepicker.convert(cropped, { + height: targetCropSize, + width: targetCropSize, + fit: 'scale', + format: 'jpg', + quality: 75, + policy: filepickerPolicy.policy, + signature: filepickerPolicy.signature + }, { path: createStorePath(self.bandDetail), access: 'public' }, + function(scaled) { + logger.debug("converted and scaled final image %o", scaled); + rest.updateBandPhoto({ + original_fpfile: determineCurrentFpfile(), + cropped_fpfile: scaled, + crop_selection: currentSelection, + id: bandId + }) + .done(updateBandPhotoSuccess) + .fail(app.ajaxError) + .always(function() { removeBandPhotoSpinner(); self.updatingBandPhoto = false;}) + }, + function(fperror) { + alert("unable to scale selection. error code: " + fperror.code); + removeBandPhotoSpinner(); + self.updatingBandPhoto = false; + }) + }) + .fail(app.ajaxError); + }, + function(fperror) { + alert("unable to crop selection. error code: " + fperror.code); + removeBandPhotoSpinner(); + self.updatingBandPhoto = false; + } + ); + }) + .fail(app.ajaxError); + } + else { + app.notify( + { title: "Upload a Band Photo First", + text: "To update your band photo, first you must upload an image using the UPLOAD button" + }, + { no_cancel: true }); + } + } + + function updateBandPhotoSuccess(response) { + $.cookie('original_fpfile_band_photo', null); + + self.bandDetail = response; + + app.notify( + { title: "Band Photo Changed", + text: "You have updated your band photo successfully." + }, + { no_cancel: true }); + } + + function onSelectRelease(event) { + } + + function onSelect(event) { + selection = event; + } + + function onChange(event) { + } + + function createStorePath(bandDetail) { + return gon.fp_upload_dir + '/' + bandDetail.id + '/' + } + + function createOriginalFilename(bandDetail) { + // get the s3 + var fpfile = bandDetail.original_fpfile_photo ? JSON.parse(bandDetail.original_fpfile_photo) : null; + return 'original_band_photo.jpg' + } + + // retrieves a file that has not yet been used as an band photo (uploaded, but not cropped) + function getWorkingFpfile() { + return JSON.parse($.cookie('original_fpfile_band_photo')) + } + + function determineCurrentFpfile() { + // precedence is as follows: + // * tempOriginal: if set, then the user is working on a new upload + // * storedOriginal: if set, then the user has previously uploaded and cropped a band photo + // * null: neither are set above + + var tempOriginal = getWorkingFpfile(); + var storedOriginal = self.bandDetail.original_fpfile_photo ? JSON.parse(self.bandDetail.original_fpfile_photo) : null; + + return tempOriginal ? tempOriginal : storedOriginal; + } + + function determineCurrentSelection(bandDetail) { + // if the cookie is set, don't use the storage selection, just default to null + return $.cookie('original_fpfile_band_photo') == null ? bandDetail.crop_selection_photo : null; + } + + function initialize() { + var screenBindings = { + 'beforeShow': beforeShow, + 'afterShow': afterShow + }; + app.bindScreen('band/setup/photo', screenBindings); + events(); + } + + this.initialize = initialize; + this.beforeShow = beforeShow; + this.afterShow = afterShow; + return this; + }; + +})(window,jQuery); \ No newline at end of file diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index c6cc63d71..f0ad75ebc 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -211,6 +211,12 @@ var cropped_fpfile = options['cropped_fpfile']; var crop_selection = options['crop_selection']; + logger.debug(JSON.stringify({ + original_fpfile : original_fpfile, + cropped_fpfile : cropped_fpfile, + crop_selection : crop_selection + })); + var url = "/api/users/" + id + "/avatar"; return $.ajax({ type: "POST", @@ -252,6 +258,60 @@ }); } + function updateBandPhoto(options) { + var id = getId(options); + + var original_fpfile = options['original_fpfile']; + var cropped_fpfile = options['cropped_fpfile']; + var crop_selection = options['crop_selection']; + + logger.debug(JSON.stringify({ + original_fpfile : original_fpfile, + cropped_fpfile : cropped_fpfile, + crop_selection : crop_selection + })); + + var url = "/api/bands/" + id + "/photo"; + return $.ajax({ + type: "POST", + dataType: "json", + url: url, + contentType: 'application/json', + processData:false, + data: JSON.stringify({ + original_fpfile : original_fpfile, + cropped_fpfile : cropped_fpfile, + crop_selection : crop_selection + }) + }); + } + + function deleteBandPhoto(options) { + var id = getId(options); + + var url = "/api/bands/" + id + "/photo"; + return $.ajax({ + type: "DELETE", + dataType: "json", + url: url, + contentType: 'application/json', + processData:false + }); + } + + function getBandPhotoFilepickerPolicy(options) { + var id = getId(options); + var handle = options && options["handle"]; + var convert = options && options["convert"] + + var url = "/api/bands/" + id + "/filepicker_policy"; + + return $.ajax(url, { + data : { handle : handle, convert: convert }, + dataType : 'json' + }); + } + function getFriends(options) { var friends = []; var id = getId(options); @@ -499,6 +559,9 @@ this.putTrackSyncChange = putTrackSyncChange; this.createBand = createBand; this.updateBand = updateBand; + this.updateBandPhoto = updateBandPhoto; + this.deleteBandPhoto = deleteBandPhoto; + this.getBandPhotoFilepickerPolicy = getBandPhotoFilepickerPolicy; this.getBand = getBand; this.createBandInvitation = createBandInvitation; this.updateBandInvitation = updateBandInvitation; diff --git a/web/app/assets/stylesheets/client/band.css.scss b/web/app/assets/stylesheets/client/band.css.scss index c907ef7d5..18f505eb1 100644 --- a/web/app/assets/stylesheets/client/band.css.scss +++ b/web/app/assets/stylesheets/client/band.css.scss @@ -17,6 +17,43 @@ font-size:14px; } +.band-setup-photo { + + .avatar-space { + color: $color2; + margin-bottom: 20px; + position:relative; + min-height:300px; + + img.preview_profile_avatar { + } + } + + + .spinner-large { + width:300px; + height:300px; + line-height: 300px; + position:absolute; + top:0; + left:0; + z-index: 2000; // to win over jcrop + } + + .no-avatar-space { + border:1px dotted $color2; + + color: $color2; + width:300px; + height:300px; + line-height: 300px; + text-align: center; + vertical-align: middle; + background-color:$ColorTextBoxBackground; + + } + } + .band-profile-header { padding:20px; height:120px; diff --git a/web/app/controllers/api_bands_controller.rb b/web/app/controllers/api_bands_controller.rb index ff9c09833..483237bae 100644 --- a/web/app/controllers/api_bands_controller.rb +++ b/web/app/controllers/api_bands_controller.rb @@ -3,7 +3,8 @@ class ApiBandsController < ApiController before_filter :api_signed_in_user, :except => [:index, :show, :follower_index] before_filter :auth_band_member, :only => [:update, :recording_create, :recording_update, :recording_destroy, - :invitation_index, :invitation_show, :invitation_create, :invitation_destroy] + :invitation_index, :invitation_show, :invitation_create, :invitation_destroy, + :update_photo, :delete_photo, :generate_filepicker_policy] respond_to :json @@ -187,6 +188,56 @@ class ApiBandsController < ApiController end end + def update_photo + original_fpfile = params[:original_fpfile] + cropped_fpfile = params[:cropped_fpfile] + crop_selection = params[:crop_selection] + + # public bucket to allow images to be available to public + @band.update_photo(original_fpfile, cropped_fpfile, crop_selection, Rails.application.config.aws_bucket_public) + + if @band.errors.any? + respond_with @band, status: :unprocessable_entity + else + respond_with @band, responder: ApiResponder, status: 200 + end + end + + def delete_photo + @band.delete_photo(Rails.application.config.aws_bucket_public) + + if @band.errors.any? + respond_with @band, status: :unprocessable_entity + else + respond_with @band, responder: ApiResponder, status: 204 + end + end + + def generate_filepicker_policy + # generates a soon-expiring filepicker policy so that a band can only upload to their own folder in their bucket + + handle = params[:handle] + + call = 'pick,convert,store' + + policy = { :expiry => (DateTime.now + 5.minutes).to_i(), + :call => call + #:path => 'avatars/' + @band.id + '/.*jpg' + } + + # if the caller specifies a handle, add it to the hash + unless handle.nil? + start = handle.rindex('/') + 1 + policy[:handle] = handle[start..-1] + end + + policy = Base64.urlsafe_encode64( policy.to_json ) + digest = OpenSSL::Digest::Digest.new('sha256') + signature = OpenSSL::HMAC.hexdigest(digest, Rails.application.config.fp_secret, policy) + + render :json => { :signature => signature, :policy => policy }, :status => :ok + end + ############################################################################# protected # ensures user is a member of the band diff --git a/web/app/views/api_bands/show.rabl b/web/app/views/api_bands/show.rabl index bcd2ed486..c893e696d 100644 --- a/web/app/views/api_bands/show.rabl +++ b/web/app/views/api_bands/show.rabl @@ -1,6 +1,7 @@ object @band -attributes :id, :name, :city, :state, :country, :location, :website, :biography, :photo_url, :logo_url, :liker_count, :follower_count, :recording_count, :session_count +attributes :id, :name, :city, :state, :country, :location, :website, :biography, :photo_url, :logo_url, :liker_count, :follower_count, :recording_count, :session_count, +:original_fpfile_photo, :cropped_fpfile_photo, :crop_selection_photo unless @band.users.nil? || @band.users.size == 0 child :users => :musicians do diff --git a/web/app/views/clients/_account_profile.html.erb b/web/app/views/clients/_account_profile.html.erb index 9a851ca1b..69e6903cc 100644 --- a/web/app/views/clients/_account_profile.html.erb +++ b/web/app/views/clients/_account_profile.html.erb @@ -1,4 +1,4 @@ - +