From c18848fa03db93a597df6ecbf67cfafc5ca73e84 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Fri, 29 Nov 2013 18:34:00 -0600 Subject: [PATCH 01/40] vtfs-884: cleanup of musicians page prepping for bands page clone --- ruby/lib/jam_ruby/models/search.rb | 49 ++++++++++--------- web/app/assets/javascripts/findMusician.js | 9 +++- .../assets/stylesheets/client/search.css.scss | 15 +----- .../views/clients/_musician_filter.html.erb | 20 ++------ 4 files changed, 41 insertions(+), 52 deletions(-) diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb index 63221d8aa..bb4f5a1f7 100644 --- a/ruby/lib/jam_ruby/models/search.rb +++ b/ruby/lib/jam_ruby/models/search.rb @@ -84,15 +84,19 @@ module JamRuby attr_accessor :user_counters, :page_num, :page_count PARAM_MUSICIAN = :srch_m + PARAM_BAND = :srch_b - M_PER_PAGE = 10 + B_PER_PAGE = M_PER_PAGE = 10 M_MILES_DEFAULT = 500 + B_MILES_DEFAULT = 0 M_ORDER_FOLLOWS = ['Most Followed', :followed] M_ORDER_PLAYS = ['Most Plays', :plays] M_ORDER_PLAYING = ['Playing Now', :playing] - M_ORDERINGS = [M_ORDER_FOLLOWS, M_ORDER_PLAYS, M_ORDER_PLAYING] - M_ORDERING_KEYS = M_ORDERINGS.collect { |oo| oo[1] } + B_ORDERINGS = M_ORDERINGS = [M_ORDER_FOLLOWS, M_ORDER_PLAYS, M_ORDER_PLAYING] + B_ORDERING_KEYS = M_ORDERING_KEYS = M_ORDERINGS.collect { |oo| oo[1] } + + B_DISTANCE_OPTS = M_DISTANCE_OPTS = [['Any', 0], [1000.to_s, 1000], [500.to_s, 500], [250.to_s, 250], [100.to_s, 100], [50.to_s, 50], [25.to_s, 25]] def self.musician_order_param(params) ordering = params[:orderby] @@ -106,27 +110,28 @@ module JamRuby .where(['minst.instrument_id = ? AND users.id IS NOT NULL', instrument]) end - location_distance, location_city = params[:distance], params[:city] - distance, latlng = nil, [] - if location_distance && location_city - if geo = MaxMindGeo.where(:city => params[:city]).limit(1).first - distance, latlng = location_distance, [geo.lat, geo.lng] - end - elsif current_user - if current_user.lat.nil? || current_user.lng.nil? - if params[:remote_ip] && (geo = MaxMindGeo.ip_lookup(params[:remote_ip])) - latlng = [geo.lat, geo.lng] if geo.lat && geo.lng + if 0 < (location_distance = params[:distance].to_i) + location_city, distance, latlng = params[:city], nil, [] + if location_distance && location_city + if geo = MaxMindGeo.where(:city => params[:city]).limit(1).first + distance, latlng = location_distance, [geo.lat, geo.lng] end - else - latlng = [current_user.lat, current_user.lng] + elsif current_user + if current_user.lat.nil? || current_user.lng.nil? + if params[:remote_ip] && (geo = MaxMindGeo.ip_lookup(params[:remote_ip])) + latlng = [geo.lat, geo.lng] if geo.lat && geo.lng + end + else + latlng = [current_user.lat, current_user.lng] + end + elsif params[:remote_ip] && (geo = MaxMindGeo.ip_lookup(params[:remote_ip])) + latlng = [geo.lat, geo.lng] if geo.lat && geo.lng + end + if latlng.present? + distance ||= location_distance || M_MILES_DEFAULT + rel = rel.where(['lat IS NOT NULL AND lng IS NOT NULL']) + .within(distance, :origin => latlng) end - elsif params[:remote_ip] && (geo = MaxMindGeo.ip_lookup(params[:remote_ip])) - latlng = [geo.lat, geo.lng] if geo.lat && geo.lng - end - if latlng.present? - distance ||= location_distance || M_MILES_DEFAULT - rel = rel.where(['lat IS NOT NULL AND lng IS NOT NULL']) - .within(distance, :origin => latlng) end sel_str = 'users.*' diff --git a/web/app/assets/javascripts/findMusician.js b/web/app/assets/javascripts/findMusician.js index 7da599797..7288e28c0 100644 --- a/web/app/assets/javascripts/findMusician.js +++ b/web/app/assets/javascripts/findMusician.js @@ -29,12 +29,12 @@ var queryString = 'srch_m=1&page='+page_num+'&'; // order by - var orderby = $('.musician-order-by').val(); + var orderby = $('#musician_order_by').val(); if (typeof orderby != 'undefined' && orderby.length > 0) { queryString += "orderby=" + orderby + '&'; } // instrument filter - var instrument = $('.instrument-list').val(); + var instrument = $('#musician_instrument').val(); if (typeof instrument != 'undefined' && !(instrument === '')) { queryString += "instrument=" + instrument + '&'; } @@ -197,6 +197,7 @@ } function events() { + /* $("#musician_query_distance").keypress(function(evt) { if (evt.which === 13) { evt.preventDefault(); @@ -204,6 +205,10 @@ } }); $('#btn-refresh-musicians').on("click", refreshDisplay); + */ + $('#musician_query_distance').change(refreshDisplay); + $('#musician_instrument').change(refreshDisplay); + $('#musician_order_by').change(refreshDisplay); $('#musician-filter-results').bind('scroll', function() { if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) { diff --git a/web/app/assets/stylesheets/client/search.css.scss b/web/app/assets/stylesheets/client/search.css.scss index 0cb2f25ff..352a3b644 100644 --- a/web/app/assets/stylesheets/client/search.css.scss +++ b/web/app/assets/stylesheets/client/search.css.scss @@ -56,20 +56,9 @@ } .query-distance-params { - float:left; - width:50px; + float: left; + width: 80px; margin-left: 10px; - -webkit-border-radius: 6px; - border-radius: 6px; - background-color:$ColorTextBoxBackground; border: none; - color:#333; - font-weight:400; - padding:0px 0px 0px 8px; - height:18px; - line-height:18px; - overflow:hidden; - -webkit-box-shadow: inset 2px 2px 3px 0px #888; - box-shadow: inset 2px 2px 3px 0px #888; } diff --git a/web/app/views/clients/_musician_filter.html.erb b/web/app/views/clients/_musician_filter.html.erb index 4a351876e..917136950 100644 --- a/web/app/views/clients/_musician_filter.html.erb +++ b/web/app/views/clients/_musician_filter.html.erb @@ -7,29 +7,19 @@ <%= content_tag(:div, :class => 'filter-element') do -%> <%= content_tag(:div, 'Instrument:', :class => 'filter-element') %> - <%= content_tag(:div, :class => 'filter-element', :id => "find-musician-instrument") do -%> - <%= select_tag(:instrument, - options_for_select([['Any', '']].concat(JamRuby::Instrument.all.collect { |ii| [ii.description, ii.id] })), - {:class => 'instrument-list'} ) %> + <%= content_tag(:div, :class => 'filter-element') do -%> + <%= select_tag(:musician_instrument, + options_for_select([['Any', '']].concat(JamRuby::Instrument.all.collect { |ii| [ii.description, ii.id] }))) %> <% end -%> <% end -%> <%= content_tag(:div, :class => 'filter-element') do -%> <%= content_tag(:div, 'Within', :class => 'filter-element') %> - <%= content_tag(:div, :class => 'query-distance-params', :style => "height:25px;") do -%> - <%= text_field_tag(:query_distance, - Search::M_MILES_DEFAULT.to_s, - :id => :musician_query_distance, - :placeholder => Search::M_MILES_DEFAULT.to_s) %> + <%= content_tag(:div, :class => 'query-distance-params') do -%> + <%= select_tag('musician_query_distance', options_for_select(Search::M_DISTANCE_OPTS, Search::M_MILES_DEFAULT)) %> <% end -%> <%= content_tag(:div, :class => 'filter-element') do -%> miles of <%= content_tag(:span, current_user.current_city(request.remote_ip), :id => 'musician-filter-city') %> <% end -%> <% end -%> - <%= content_tag(:div, - link_to('REFRESH', '#', - :id => 'btn-refresh-musicians', - :style => 'text-decoration:none', - :class => 'button-grey'), - :class => 'right mr10') %> <% end -%> From c49406d467b71b7f5f437692fc90431359e145bb Mon Sep 17 00:00:00 2001 From: Daniel Weigh Date: Sat, 7 Dec 2013 12:31:02 -0500 Subject: [PATCH 02/40] VRFS-294 Resizing Create Session View tweaks for ~1024 px width --- .../stylesheets/client/createSession.css.scss | 52 ++-- web/app/views/clients/_createSession.html.erb | 281 +++++++++--------- 2 files changed, 165 insertions(+), 168 deletions(-) diff --git a/web/app/assets/stylesheets/client/createSession.css.scss b/web/app/assets/stylesheets/client/createSession.css.scss index 0979239cd..8d012b761 100644 --- a/web/app/assets/stylesheets/client/createSession.css.scss +++ b/web/app/assets/stylesheets/client/createSession.css.scss @@ -1,25 +1,28 @@ -.session-left { - width:40%; - float:left; - padding-top:10px; - margin-left:35px; +.session-wrapper { + padding: 0 35px; + white-space: initial; + + > div.session { + width: 50%; + padding-top: 10px; + + &.right { + font-size: 13px; + } + } } +#btn-choose-friends { + margin:0; +} #create-session-genre select, #create-session-band select { - width:145px; + min-width:140px; } #find-session-genre select, #find-session-musician select { width:145px; } -.session-right { - width:50%; - float:right; - font-size:13px; - padding-top:10px; - margin-right:35px; -} .session-description { padding:5px; @@ -32,12 +35,6 @@ line-height:17px; } -.friendbox { - padding:5px; - height:60px; - width:75%; -} - .terms-checkbox { float:left; display:block; @@ -51,19 +48,22 @@ white-space:normal; } -div.friendbox { +.friendbox { background-color:#c5c5c5; border:none; -webkit-box-shadow: inset 2px 2px 3px 0px #888; box-shadow: inset 2px 2px 3px 0px #888; color:#333; -} + padding:5px; + height:60px; -div.friendbox input[type=text] { - -webkit-box-shadow: inset 0px 0px 0px 0px #888; - box-shadow: inset 0px 0px 0px 0px #888; - color:#666; - font-style:italic; + input[type=text] { + -webkit-box-shadow: inset 0px 0px 0px 0px #888; + box-shadow: inset 0px 0px 0px 0px #888; + color:#666; + font-style:italic; + + } } .invitation { diff --git a/web/app/views/clients/_createSession.html.erb b/web/app/views/clients/_createSession.html.erb index f4bf56b7b..dd932298b 100644 --- a/web/app/views/clients/_createSession.html.erb +++ b/web/app/views/clients/_createSession.html.erb @@ -14,151 +14,148 @@
-
+
+
-

session info

+

session info

+
-
- -
-
Genre:
-
- <%= render "genreSelector" %> -
-
- -
-
Band:
-
- -
-
- -

- -
-
Description:
-
- -
-
- -
- -
Musician Access:
-
-
- -
- -
- - -
-
- -

- -
Fan Access:
-
-
- -
- -
- - -
-
-
- -
-

invite musicians

- -
- -
-
- Start typing friends' names or: -
- -
- -
-
- - -
-
- -
- -
- Invite friends and contacts to join you on JamKazam from: -
-
- - - - -
-
-
- -
-
- -
-
- I agree that intellectual property ownership of any musical works created during this session shall be governed by the terms of the Creative Commons CC BY-NC-SA license in accordance with the JamKazam Terms of Service. -
-
-
-
-
+
+
Description:
- CANCEL - JAM! + +
+
+ +
+
Genre:
+
+ <%= render "genreSelector" %> +
+
+ +
+
Band:
+
+ +
+
+ +

+ +
Musician Access:
+
+
+ +
+ +
+ + +
+
+ +

+ +
Fan Access:
+
+
+ +
+ +
+ + +
+
+
+ +
+

invite musicians

+ +
+
+ +
+ Start typing friends' names or: +
+
+
+
+ + +
+
+ +
+ +
+ Invite friends and contacts to join you on JamKazam from: +
+
+ + + + +
+
+
+ +
+
+ +
+
+ I agree that intellectual property ownership of any musical works created during this session shall be governed by the terms of the Creative Commons CC BY-NC-SA license in accordance with the JamKazam Terms of Service. +
+
+
+
+
+
+ CANCEL + JAM! +
From 5856c5d1769ff8d86acc475d7c582b2489d0ead5 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Sat, 7 Dec 2013 20:45:24 -0500 Subject: [PATCH 03/40] VRFS-876 allow user to remove band members --- web/app/assets/javascripts/bandProfile.js | 33 +++++++++++++++++---- web/app/assets/javascripts/jam_rest.js | 12 ++++++++ web/app/controllers/api_bands_controller.rb | 2 ++ web/app/views/clients/_bandProfile.html.erb | 2 +- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/web/app/assets/javascripts/bandProfile.js b/web/app/assets/javascripts/bandProfile.js index 60c63f967..7551163e3 100644 --- a/web/app/assets/javascripts/bandProfile.js +++ b/web/app/assets/javascripts/bandProfile.js @@ -5,6 +5,7 @@ context.JK = context.JK || {}; context.JK.BandProfileScreen = function(app) { var logger = context.JK.logger; + var rest = context.JK.Rest(); var bandId; var isMember = false; var band = {}; @@ -59,7 +60,7 @@ configureBandFollowingButton(true); } else { - configureMemberFollowingButton(true); + configureMemberFollowingButton(true, id); } }, error: app.ajaxError @@ -350,7 +351,6 @@ } function bindPendingMembers() { - $("#band-profile-members").append("

Pending Band Invitations

"); var url = "/api/bands/" + bandId + "/musicians?pending=true"; $.ajax({ type: "GET", @@ -359,7 +359,10 @@ async: false, processData:false, success: function(response) { - bindMusicians(response); + if (response && response.length > 0) { + $("#band-profile-members").append("

Pending Band Invitations

"); + bindMusicians(response); + } }, error: app.ajaxError }); @@ -400,12 +403,34 @@ var following = isFollowingMember(musician.id); configureMemberFollowingButton(following, musician.id); + configureRemoveMemberButton(musician.id); + // TODO: wire up Friend button click handler // var friend = isFriend(musician.id); // configureMemberFriendButton(friend, musician.id); }); } + function configureRemoveMemberButton(userId) { + + var $divMember = $('div[user-id=' + userId + ']', '#band-profile-members'); + var $btnRemoveMember = $divMember.find('#btn-remove-member'); + if (isMember) { + $btnRemoveMember.show(); + $btnRemoveMember.unbind("click"); + $btnRemoveMember.click(function() { + rest.removeBandMember(bandId, userId) + .done(function() { + $divMember.remove(); + }) + .fail(app.ajaxError); + }); + } + else { + $btnRemoveMember.hide(); + } + } + // TODO: refactor // checks if person viewing the profile is also a band member function setIsMember() { @@ -441,12 +466,10 @@ if (isMember) { $("#btn-follow-band").hide(); - $("#btn-edit-band-members").show(); $("#btn-edit-band-profile").show(); } else { $("#btn-follow-band").show(); - $("#btn-edit-band-members").hide(); $("#btn-edit-band-profile").hide(); } diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index 648ced0ff..e2c44c86c 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -115,6 +115,17 @@ }); } + function removeBandMember(bandId, userId) { + var url = "/api/bands/" + bandId + "/musicians/" + userId; + return $.ajax({ + type: "DELETE", + dataType: "json", + url: url, + async: false, + processData:false + }); + } + function getSession(id) { var url = "/api/sessions/" + id; return $.ajax({ @@ -484,6 +495,7 @@ this.getBand = getBand; this.createBandInvitation = createBandInvitation; this.updateBandInvitation = updateBandInvitation; + this.removeBandMember = removeBandMember; return this; }; diff --git a/web/app/controllers/api_bands_controller.rb b/web/app/controllers/api_bands_controller.rb index b3ca1e623..ff9c09833 100644 --- a/web/app/controllers/api_bands_controller.rb +++ b/web/app/controllers/api_bands_controller.rb @@ -65,7 +65,9 @@ class ApiBandsController < ApiController def musician_destroy unless params[:id].blank? || params[:user_id].blank? + BandMusician.delete_all "(band_id = '#{params[:id]}' AND user_id = '#{params[:user_id]}')" end + render :json => {}, :status => 202 end ###################### FOLLOWERS ######################## diff --git a/web/app/views/clients/_bandProfile.html.erb b/web/app/views/clients/_bandProfile.html.erb index 04e40c750..12c321312 100644 --- a/web/app/views/clients/_bandProfile.html.erb +++ b/web/app/views/clients/_bandProfile.html.erb @@ -19,7 +19,6 @@

@@ -92,6 +91,7 @@ {biography}

PROFILE   FOLLOW   + REMOVE MEMBER  
From 0bad5573b2b03a605f3711d38a60828cb7b61354 Mon Sep 17 00:00:00 2001 From: Daniel Weigh Date: Sun, 8 Dec 2013 12:12:26 -0500 Subject: [PATCH 04/40] VRFS-294 Resizing Create Session View tweaks for ~1024 px width. enables scrolling within the session container for short screens. --- .../stylesheets/client/createSession.css.scss | 13 ++++++++++++- web/app/views/clients/_createSession.html.erb | 11 ++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/web/app/assets/stylesheets/client/createSession.css.scss b/web/app/assets/stylesheets/client/createSession.css.scss index 8d012b761..6c3729fb2 100644 --- a/web/app/assets/stylesheets/client/createSession.css.scss +++ b/web/app/assets/stylesheets/client/createSession.css.scss @@ -1,5 +1,16 @@ +.create-session { + .content { + .content-head { + position:absolute; + z-index:1; + padding: 4px 0; + width:100% + } + } +} + .session-wrapper { - padding: 0 35px; + padding: 29px 35px 10px; white-space: initial; > div.session { diff --git a/web/app/views/clients/_createSession.html.erb b/web/app/views/clients/_createSession.html.erb index dd932298b..406e50a9d 100644 --- a/web/app/views/clients/_createSession.html.erb +++ b/web/app/views/clients/_createSession.html.erb @@ -1,5 +1,5 @@ -
+
@@ -10,8 +10,8 @@ <%= render "screen_navigation" %>
-
-
+
+
@@ -159,10 +159,11 @@
+
-
- + +
From 1b7706582611a4b66ee5f5f8f5f43e52779dbf16 Mon Sep 17 00:00:00 2001 From: Daniel Weigh Date: Sun, 8 Dec 2013 13:07:36 -0500 Subject: [PATCH 05/40] VRFS-294 Resizing Create Session View tweaks for ~1024 px width. tweak to content-icon --- web/app/assets/stylesheets/client/createSession.css.scss | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/app/assets/stylesheets/client/createSession.css.scss b/web/app/assets/stylesheets/client/createSession.css.scss index 6c3729fb2..a14c37c67 100644 --- a/web/app/assets/stylesheets/client/createSession.css.scss +++ b/web/app/assets/stylesheets/client/createSession.css.scss @@ -4,7 +4,11 @@ position:absolute; z-index:1; padding: 4px 0; - width:100% + width:100%; + + .content-icon { + margin-left:4px; + } } } } From 833eb45379270cec2118b5b0e85f75dcc8c6a498 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Sun, 8 Dec 2013 22:31:49 -0500 Subject: [PATCH 06/40] VRFS-878 use IP address to default location for band setup --- web/app/assets/javascripts/band_setup.js | 75 +++++++++++-------- web/app/assets/javascripts/jam_rest.js | 7 ++ .../api_maxmind_requests_controller.rb | 6 ++ web/config/routes.rb | 1 + 4 files changed, 59 insertions(+), 30 deletions(-) diff --git a/web/app/assets/javascripts/band_setup.js b/web/app/assets/javascripts/band_setup.js index ae27f3e27..3d51a93db 100644 --- a/web/app/assets/javascripts/band_setup.js +++ b/web/app/assets/javascripts/band_setup.js @@ -246,7 +246,17 @@ } else { loadGenres(); - loadCountries(); + + rest.getResolvedLocation() + .done(function(location) { + loadCountries(location.country, function() { + loadRegions(location.region, function() { + loadCities(location.city); + }); + }); + }); + + $("#band-setup-title").html("set up band"); $("#btn-band-setup-save").html("CREATE BAND"); } @@ -261,7 +271,7 @@ loadGenres(band.genres); loadCountries(band.country, function() { - loadRegions(band.state, function () { + loadRegions(band.region, function() { loadCities(band.city); }); }); @@ -357,24 +367,26 @@ nilOption.text(nilOptionText); $region.append(nilOption); - rest.getRegions({'country': selectedCountry}).done(function(response) { - $.each(response["regions"], function(index, region) { - if(!region) return; - var option = $(''); - option.text(region); - option.attr("value", region); + if (selectedCountry) { + rest.getRegions({'country': selectedCountry}).done(function(response) { + $.each(response["regions"], function(index, region) { + if(!region) return; + var option = $(''); + option.text(region); + option.attr("value", region); - if (initialRegion === region) { - option.attr("selected", "selected"); + if (initialRegion === region) { + option.attr("selected", "selected"); + } + + $region.append(option); + }); + + if (onRegionsLoaded) { + onRegionsLoaded(); } - - $region.append(option); }); - - if (onRegionsLoaded) { - onRegionsLoaded(); - } - }); + } } function loadCities(initialCity) { @@ -387,20 +399,22 @@ nilOption.text(nilOptionText); $city.append(nilOption); - rest.getCities({'country': selectedCountry, 'region': selectedRegion}) .done(function(response) { - $.each(response["cities"], function(index, city) { - if(!city) return; - var option = $(''); - option.text(city); - option.attr("value", city); + if (selectedCountry && selectedRegion) { + rest.getCities({'country': selectedCountry, 'region': selectedRegion}) .done(function(response) { + $.each(response["cities"], function(index, city) { + if(!city) return; + var option = $(''); + option.text(city); + option.attr("value", city); - if (initialCity === city) { - option.attr("selected", "selected"); - } + if (initialCity === city) { + option.attr("selected", "selected"); + } - $city.append(option); + $city.append(option); + }); }); - }); + } } function friendSelectorCallback(newSelections) { @@ -467,13 +481,14 @@ $('#band-country').on('change', function(evt) { evt.stopPropagation(); - loadRegions(''); + loadRegions(); + loadCities(); return false; }); $('#band-region').on('change', function(evt) { evt.stopPropagation(); - loadCities(''); + loadCities(); return false; }); diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index e2c44c86c..c6cc63d71 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -184,6 +184,12 @@ }); } + function getResolvedLocation() { + return $.ajax('/api/resolved_location', { + dataType: 'json' + }); + } + function getInstruments(options) { return $.ajax('/api/instruments', { data : { }, @@ -466,6 +472,7 @@ this.getRegions = getRegions; this.getCountries = getCountries; this.getIsps = getIsps; + this.getResolvedLocation = getResolvedLocation; this.getInstruments = getInstruments; this.getGenres = getGenres; this.updateAvatar = updateAvatar; diff --git a/web/app/controllers/api_maxmind_requests_controller.rb b/web/app/controllers/api_maxmind_requests_controller.rb index 5173c6754..98c0cf8b3 100644 --- a/web/app/controllers/api_maxmind_requests_controller.rb +++ b/web/app/controllers/api_maxmind_requests_controller.rb @@ -34,4 +34,10 @@ class ApiMaxmindRequestsController < ApiController end end + # returns location hash (country, region, state) based on requesting IP + def resolved_location + location = MaxMindManager.lookup(request.remote_ip) + render :json => { :country => location[:country], :region => location[:state], :city => location[:city] }, :status => 200 + end + end \ No newline at end of file diff --git a/web/config/routes.rb b/web/config/routes.rb index 34d492721..6e7974b7f 100644 --- a/web/config/routes.rb +++ b/web/config/routes.rb @@ -259,6 +259,7 @@ SampleApp::Application.routes.draw do match '/regions' => 'api_maxmind_requests#regions', :via => :get match '/cities' => 'api_maxmind_requests#cities', :via => :get match '/isps' => 'api_maxmind_requests#isps', :via => :get + match '/resolved_location' => 'api_maxmind_requests#resolved_location', :via => :get # Recordings From 4c804d2f946b0822faaeec0f9223fa85cd35bea3 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 9 Dec 2013 07:15:59 -0600 Subject: [PATCH 07/40] vrfs-884: added band geocoding; inital band filtering tests; refactoring musicians filter page --- db/manifest | 3 +- db/up/bands_geocoding.sql | 4 + ruby/lib/jam_ruby/models/band.rb | 24 ++ ruby/lib/jam_ruby/models/max_mind_geo.rb | 28 +++ ruby/lib/jam_ruby/models/search.rb | 106 ++++++--- .../models/band_filter_search_spec.rb | 218 ++++++++++++++++++ .../jam_ruby/models/band_location_spec.rb | 39 ++++ ruby/spec/jam_ruby/models/band_search_spec.rb | 2 +- web/app/views/clients/_bands.html.erb | 27 ++- web/app/views/clients/_musicians.html.erb | 2 +- web/app/views/clients/_web_filter.html.erb | 36 +++ 11 files changed, 446 insertions(+), 43 deletions(-) create mode 100644 db/up/bands_geocoding.sql create mode 100644 ruby/spec/jam_ruby/models/band_filter_search_spec.rb create mode 100644 ruby/spec/jam_ruby/models/band_location_spec.rb create mode 100644 web/app/views/clients/_web_filter.html.erb diff --git a/db/manifest b/db/manifest index 9f19d8fe7..e047ce7e2 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 +bands_geocoding.sql diff --git a/db/up/bands_geocoding.sql b/db/up/bands_geocoding.sql new file mode 100644 index 000000000..cf612ac0e --- /dev/null +++ b/db/up/bands_geocoding.sql @@ -0,0 +1,4 @@ +ALTER TABLE bands ADD COLUMN lat NUMERIC(15,10); +ALTER TABLE bands ADD COLUMN lng NUMERIC(15,10); + +UPDATE bands SET country = 'US' WHERE country = 'USA'; diff --git a/ruby/lib/jam_ruby/models/band.rb b/ruby/lib/jam_ruby/models/band.rb index 5f47cdb9d..97200e21a 100644 --- a/ruby/lib/jam_ruby/models/band.rb +++ b/ruby/lib/jam_ruby/models/band.rb @@ -7,6 +7,8 @@ module JamRuby validates :biography, no_profanity: true + before_save :check_lat_lng + # musicians has_many :band_musicians, :class_name => "JamRuby::BandMusician" has_many :users, :through => :band_musicians, :class_name => "JamRuby::User" @@ -187,6 +189,28 @@ module JamRuby return band end + def check_lat_lng + if (city_changed? || state_changed? || country_changed?) + update_lat_lng + end + end + + def update_lat_lng + if self.city + query = { :city => self.city } + query[:region] = self.state unless self.state.blank? + query[:country] = self.country unless self.country.blank? + if geo = MaxMindGeo.where(query).limit(1).first + if geo.lat && geo.lng && (self.lat != geo.lat || self.lng != geo.lng) + self.lat, self.lng = geo.lat, geo.lng + return true + end + end + end + self.lat, self.lng = nil, nil + false + end + private def self.validate_genres(genres, is_nil_ok) if is_nil_ok && genres.nil? diff --git a/ruby/lib/jam_ruby/models/max_mind_geo.rb b/ruby/lib/jam_ruby/models/max_mind_geo.rb index 81868c4cd..713938552 100644 --- a/ruby/lib/jam_ruby/models/max_mind_geo.rb +++ b/ruby/lib/jam_ruby/models/max_mind_geo.rb @@ -40,7 +40,35 @@ module JamRuby end end User.find_each { |usr| usr.update_lat_lng } + Band.find_each { |bnd| bnd.update_lat_lng } end + + def self.where_latlng(relation, params, current_user=nil) + if 0 < (distance = params[:distance].to_i) + latlng = [] + if location_city = params[:city] + if geo = self.where(:city => params[:city]).limit(1).first + latlng = [geo.lat, geo.lng] + end + elsif current_user + if current_user.lat.nil? || current_user.lng.nil? + if params[:remote_ip] && (geo = self.ip_lookup(params[:remote_ip])) + latlng = [geo.lat, geo.lng] if geo.lat && geo.lng + end + else + latlng = [current_user.lat, current_user.lng] + end + elsif params[:remote_ip] && (geo = self.ip_lookup(params[:remote_ip])) + latlng = [geo.lat, geo.lng] if geo.lat && geo.lng + end + if latlng.present? + relation = relation.where(['lat IS NOT NULL AND lng IS NOT NULL']) + .within(distance, :origin => latlng) + end + end + relation + end + end end diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb index bb4f5a1f7..3ab843f4a 100644 --- a/ruby/lib/jam_ruby/models/search.rb +++ b/ruby/lib/jam_ruby/models/search.rb @@ -93,14 +93,14 @@ module JamRuby M_ORDER_FOLLOWS = ['Most Followed', :followed] M_ORDER_PLAYS = ['Most Plays', :plays] M_ORDER_PLAYING = ['Playing Now', :playing] - B_ORDERINGS = M_ORDERINGS = [M_ORDER_FOLLOWS, M_ORDER_PLAYS, M_ORDER_PLAYING] + ORDERINGS = B_ORDERINGS = M_ORDERINGS = [M_ORDER_FOLLOWS, M_ORDER_PLAYS, M_ORDER_PLAYING] B_ORDERING_KEYS = M_ORDERING_KEYS = M_ORDERINGS.collect { |oo| oo[1] } - B_DISTANCE_OPTS = M_DISTANCE_OPTS = [['Any', 0], [1000.to_s, 1000], [500.to_s, 500], [250.to_s, 250], [100.to_s, 100], [50.to_s, 50], [25.to_s, 25]] + DISTANCE_OPTS = B_DISTANCE_OPTS = M_DISTANCE_OPTS = [['Any', 0], [1000.to_s, 1000], [500.to_s, 500], [250.to_s, 250], [100.to_s, 100], [50.to_s, 50], [25.to_s, 25]] - def self.musician_order_param(params) + def self.order_param(params, keys=M_ORDERING_KEYS) ordering = params[:orderby] - ordering.blank? ? M_ORDERING_KEYS[0] : M_ORDERING_KEYS.detect { |oo| oo.to_s == ordering } + ordering.blank? ? keys[0] : keys.detect { |oo| oo.to_s == ordering } end def self.musician_search(params={}, current_user=nil) @@ -110,32 +110,10 @@ module JamRuby .where(['minst.instrument_id = ? AND users.id IS NOT NULL', instrument]) end - if 0 < (location_distance = params[:distance].to_i) - location_city, distance, latlng = params[:city], nil, [] - if location_distance && location_city - if geo = MaxMindGeo.where(:city => params[:city]).limit(1).first - distance, latlng = location_distance, [geo.lat, geo.lng] - end - elsif current_user - if current_user.lat.nil? || current_user.lng.nil? - if params[:remote_ip] && (geo = MaxMindGeo.ip_lookup(params[:remote_ip])) - latlng = [geo.lat, geo.lng] if geo.lat && geo.lng - end - else - latlng = [current_user.lat, current_user.lng] - end - elsif params[:remote_ip] && (geo = MaxMindGeo.ip_lookup(params[:remote_ip])) - latlng = [geo.lat, geo.lng] if geo.lat && geo.lng - end - if latlng.present? - distance ||= location_distance || M_MILES_DEFAULT - rel = rel.where(['lat IS NOT NULL AND lng IS NOT NULL']) - .within(distance, :origin => latlng) - end - end + rel = MaxMindGeo.where_latlng(rel, params, current_user) sel_str = 'users.*' - case ordering = self.musician_order_param(params) + case ordering = self.order_param(params) when :plays # FIXME: double counting? sel_str = "COUNT(records)+COUNT(sessions) AS play_count, #{sel_str}" rel = rel.joins("LEFT JOIN music_sessions AS sessions ON sessions.user_id = users.id") @@ -263,5 +241,77 @@ module JamRuby end end + def self.band_search(params={}, current_user=nil) + rel = Band.scoped + # rel = Arel::Table.new(:bands) + + unless (genre = params[:genre]).blank? + rel = Band.joins("RIGHT JOIN band_genres AS bgenres ON bgenres.band_id = bands.id") + .where(['bgenres.genre_id = ? AND bands.id IS NOT NULL', genre]) + end + + rel = MaxMindGeo.where_latlng(rel, params, current_user) + + sel_str = 'bands.*' + case ordering = self.order_param(params) + when :plays # FIXME: double counting? + sel_str = "COUNT(records)+COUNT(sessions) AS play_count, #{sel_str}" + rel = rel.joins("LEFT JOIN music_sessions AS sessions ON sessions.user_id = users.id") + .joins("LEFT JOIN recordings AS records ON records.owner_id = users.id") + .group("users.id") + .order("play_count DESC, users.created_at DESC") + when :followed + sel_str = "COUNT(follows) AS search_follow_count, #{sel_str}" + rel = rel.joins("LEFT JOIN bands_followers AS follows ON follows.band_id = bands.id") + .group("bands.id") + .order("COUNT(follows) DESC, bands.created_at DESC") + when :playing + rel = rel.joins("LEFT JOIN connections ON connections.user_id = users.id") + .where(['connections.music_session_id IS NOT NULL AND connections.aasm_state != ?', + 'expired']) + .order("users.created_at DESC") + end + + rel = rel.select(sel_str) + perpage = [(params[:per_page] || M_PER_PAGE).to_i, 100].min + page = [params[:page].to_i, 1].max + rel = rel.paginate(:page => page, :per_page => perpage) + rel = rel.includes([:users]) + + objs = rel.all + srch = Search.new + srch.page_num, srch.page_count = page, objs.total_pages + srch.band_results_for_user(objs, current_user) + end + + def band_results_for_user(results, user) + @search_type, @bands = PARAM_BAND, results + if user + @user_counters = results.inject({}) { |hh,val| hh[val.id] = []; hh } + mids = "'#{@bands.map(&:id).join("','")}'" + + # this gets counts for each search result + results.each do |bb| + counters = { } + counters[COUNT_FOLLOW] = BandFollowing.where(:band_id => bb.id).count + # counters[COUNT_RECORD] = ClaimedRecording.where(:band_id => bb.id).count + # counters[COUNT_SESSION] = MusicSession.where(:band_id => bb.id).count + @user_counters[bb.id] << counters + end + + # this section determines follow/like/friend status for each search result + # so that action links can be activated or not + + rel = Band.select("bands.id AS bid") + rel = rel.joins("LEFT JOIN bands_followers AS follows ON follows.follower_id = '#{user.id}'") + rel = rel.where(["bands.id IN (#{mids}) AND follows.band_id = bands.id"]) + rel.all.each { |val| @user_counters[val.bid] << RESULT_FOLLOW } + + else + @user_counters = {} + end + self + end + end end diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb new file mode 100644 index 000000000..b487890bb --- /dev/null +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -0,0 +1,218 @@ +require 'spec_helper' + +describe 'Band search' do + + before(:each) do + @geocode1 = FactoryGirl.create(:geocoder) + @geocode2 = FactoryGirl.create(:geocoder) + @bands = [] + @bands << @band1 = FactoryGirl.create(:band) + @bands << @band2 = FactoryGirl.create(:band) + @bands << @band3 = FactoryGirl.create(:band) + @bands << @band4 = FactoryGirl.create(:band) + + @bands.each do |bb| + FactoryGirl.create(:band_musician, :band => bb, :user => FactoryGirl.create(:user)) + (rand(4)+1).downto(1) do |nn| + FactoryGirl.create(:band_musician, :band => bb, :user => FactoryGirl.create(:user)) + end + end + + end + + context 'default filter settings' do + + it "finds all bands" do + # expects all the bands + num = Band.count + results = Search.band_search({ :per_page => num }) + expect(results.bands.count).to eq(num) + end + + it "finds bands with proper ordering" do + # the ordering should be create_at since no followers exist + expect(BandFollower.count).to eq(0) + results = Search.band_search({ :per_page => Band.count }) + results.bands.each_with_index do |uu, idx| + expect(uu.id).to eq(@bands.reverse[idx].id) + end + end + + it "sorts bands by followers" do + users = [] + 4.downto(1) do |nn| + users << FactoryGirl.create(:user) + end + + # establish sorting order + @band4.followers.concat(users[1..-1]) + @band3.followers.concat(users[1..3]) + @band2.followers.concat(users[0]) + @bands.map(&:reload) + + expect(@band4.followers.count).to be 3 + expect(BandFollower.count).to be 7 + + # refresh the order to ensure it works right + @band2.followers.concat(users[1..-1]) + results = Search.band_search({ :per_page => @bands.size }, users[0]) + expect(results.bands[0].id).to eq(@band2.id) + + # check the follower count for given entry + expect(results.bands[0].search_follow_count.to_i).not_to eq(0) + # check the follow relationship between current_user and result + expect(results.is_follower?(@band2)).to be true + end + + it 'paginates properly' do + pending + # make sure pagination works right + params = { :per_page => 2, :page => 1 } + results = Search.band_search(params) + expect(results.bands.count).to be 2 + end + + end + + def make_recording(usr) + connection = FactoryGirl.create(:connection, :band => usr) + instrument = FactoryGirl.create(:instrument, :description => 'a great instrument') + track = FactoryGirl.create(:track, :connection => connection, :instrument => instrument) + music_session = FactoryGirl.create(:music_session, :creator => usr, :band_access => true) + music_session.connections << connection + music_session.save + recording = Recording.start(music_session, usr) + recording.stop + recording.reload + genre = FactoryGirl.create(:genre) + recording.claim(usr, "name", "description", genre, true, true) + recording.reload + recording + end + + def make_session(usr) + connection = FactoryGirl.create(:connection, :band => usr) + music_session = FactoryGirl.create(:music_session, :creator => usr, :band_access => true) + music_session.connections << connection + music_session.save + end + +=begin + context 'band stat counters' do + + it "displays bands top followings" do + pending + @band4.followers.concat([@band4]) + @band3.followers.concat([@band4]) + @band2.followers.concat([@band4]) + expect(@band4.top_followings.count).to be 3 + expect(@band4.top_followings.map(&:id)).to match_array((@bands - [@band1]).map(&:id)) + end + + it "recording stat shows recording count" do + pending + recording = make_recording(@band1) + expect(recording.bands.length).to be 1 + expect(recording.bands.first).to eq(@band1) + @band1.reload + expect(@band1.recordings.length).to be 1 + expect(@band1.recordings.first).to eq(recording) + expect(recording.claimed_recordings.length).to be 1 + expect(@band1.recordings.detect { |rr| rr == recording }).to_not be_nil + + results = Search.band_search({},@band1) + uu = results.bands.detect { |mm| mm.id == @band1.id } + expect(uu).to_not be_nil + + expect(results.record_count(uu)).to be 1 + expect(results.session_count(uu)).to be 1 + end + + end + + context 'band sorting' do + + it "by plays" do + pending + make_recording(@band1) + # order results by num recordings + results = Search.band_search({ :orderby => 'plays' }, @band2) + expect(results.bands[0].id).to eq(@band1.id) + + # add more data and make sure order still correct + make_recording(@band2); make_recording(@band2) + results = Search.band_search({ :orderby => 'plays' }, @band2) + expect(results.bands[0].id).to eq(@band2.id) + end + + it "by now playing" do + pending + # should get 1 result with 1 active session + make_session(@band3) + results = Search.band_search({ :orderby => 'playing' }, @band2) + expect(results.bands.count).to be 1 + expect(results.bands.first.id).to eq(@band3.id) + + # should get 2 results with 2 active sessions + # sort order should be created_at DESC + make_session(@band4) + results = Search.band_search({ :orderby => 'playing' }, @band2) + expect(results.bands.count).to be 2 + expect(results.bands[0].id).to eq(@band4.id) + expect(results.bands[1].id).to eq(@band3.id) + end + + end + + context 'filter settings' do + it "searches musicisns for an instrument" do + pending + minst = FactoryGirl.create(:band_instrument, { + :band => @band1, + :instrument => Instrument.find('tuba') }) + @band1.band_instruments << minst + @band1.reload + ii = @band1.instruments.detect { |inst| inst.id == 'tuba' } + expect(ii).to_not be_nil + results = Search.band_search({ :instrument => ii.id }) + results.bands.each do |rr| + expect(rr.instruments.detect { |inst| inst.id=='tuba' }.id).to eq(ii.id) + end + expect(results.count).to be 1 + end + + it "finds bands within a given distance of given location" do + pending + num = Band.count + expect(@band1.lat).to_not be_nil + # short distance + results = Search.band_search({ :per_page => num, + :distance => 10, + :city => 'Apex' }, @band1) + expect(results.count).to be num + # long distance + results = Search.band_search({ :per_page => num, + :distance => 1000, + :city => 'Miami', + :state => 'FL' }, @band1) + expect(results.count).to be num + end + + it "finds bands within a given distance of bands location" do + pending + expect(@band1.lat).to_not be_nil + # uses the location of @band1 + results = Search.band_search({ :distance => 10, :per_page => Band.count }, @band1) + expect(results.count).to be Band.count + end + + it "finds no bands within a given distance of location" do + pending + expect(@band1.lat).to_not be_nil + results = Search.band_search({ :distance => 10, :city => 'San Francisco' }, @band1) + expect(results.count).to be 0 + end + + end +=end +end diff --git a/ruby/spec/jam_ruby/models/band_location_spec.rb b/ruby/spec/jam_ruby/models/band_location_spec.rb new file mode 100644 index 000000000..fae562a53 --- /dev/null +++ b/ruby/spec/jam_ruby/models/band_location_spec.rb @@ -0,0 +1,39 @@ +require 'spec_helper' + +describe Band do + + before do + @geocode1 = FactoryGirl.create(:geocoder) + @geocode2 = FactoryGirl.create(:geocoder) + @band = FactoryGirl.create(:band) + end + + describe "with profile location data" do + it "should have lat/lng values" do + geo = MaxMindGeo.find_by_city(@band.city) + @band.lat.should == geo.lat + @band.lng.should == geo.lng + end + it "should have updated lat/lng values" do + @band.update_attributes({ :city => @geocode2.city, + :state => @geocode2.region, + :country => @geocode2.country, + }) + geo = MaxMindGeo.find_by_city(@band.city) + @band.lat.should == geo.lat + @band.lng.should == geo.lng + end + end + + describe "without location data" do + it "should have nil lat/lng values without address" do + @band.update_attributes({ :city => nil, + :state => nil, + :country => nil, + }) + @band.lat.should == nil + @band.lng.should == nil + end + end + +end diff --git a/ruby/spec/jam_ruby/models/band_search_spec.rb b/ruby/spec/jam_ruby/models/band_search_spec.rb index 2af217b3f..ce9ca8767 100644 --- a/ruby/spec/jam_ruby/models/band_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_search_spec.rb @@ -5,7 +5,7 @@ describe User do let(:user) { FactoryGirl.create(:user) } before(:each) do - + @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) end diff --git a/web/app/views/clients/_bands.html.erb b/web/app/views/clients/_bands.html.erb index 8505890b1..417f3446d 100644 --- a/web/app/views/clients/_bands.html.erb +++ b/web/app/views/clients/_bands.html.erb @@ -1,13 +1,16 @@ -
-
- -
- <%= image_tag "content/icon_bands.png", {:height => 19, :width => 19} %> -
- -

bands

- <%= render "screen_navigation" %> -
-

This feature not yet implemented

-
+<%= content_tag(:div, :layout => 'screen', 'layout-id' => 'bands', :class => "screen secondary") do -%> + <%= content_tag(:div, :class => :content) do -%> + <%= content_tag(:div, :class => 'content-head') do -%> + <%= content_tag(:div, image_tag("content/icon_bands.png", {:height => 19, :width => 19}), :class => 'content-icon') %> + <%= content_tag(:h1, 'bands') %> + <%= render "screen_navigation" %> + <% end -%> + <%= form_tag('', :id => 'find-band-form') do -%> + <%= content_tag(:div, render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_BAND}), :class => 'band-filter', :id => 'session-controls') %> + <%= content_tag(:div, :class => 'content-scroller') do -%> + <%= content_tag(:div, content_tag(:div, '', :id => 'band-filter-results'), :class => 'content-wrapper band-wrapper') %> + <% end -%> + <% end -%> + <% end -%> +<% end -%> diff --git a/web/app/views/clients/_musicians.html.erb b/web/app/views/clients/_musicians.html.erb index 3d3e25793..973b93880 100644 --- a/web/app/views/clients/_musicians.html.erb +++ b/web/app/views/clients/_musicians.html.erb @@ -7,7 +7,7 @@ <%= render "screen_navigation" %> <% end -%> <%= form_tag('', :id => 'find-musician-form') do -%> - <%= content_tag(:div, render(:partial => "musician_filter"), :class => 'musician-filter', :id => 'session-controls') %> + <%= content_tag(:div, render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_MUSICIAN}), :class => 'musician-filter', :id => 'session-controls') %> <%= content_tag(:div, :class => 'content-scroller') do -%> <%= content_tag(:div, content_tag(:div, '', :id => 'musician-filter-results'), :class => 'content-wrapper musician-wrapper') %> <% end -%> diff --git a/web/app/views/clients/_web_filter.html.erb b/web/app/views/clients/_web_filter.html.erb new file mode 100644 index 000000000..16568bfe6 --- /dev/null +++ b/web/app/views/clients/_web_filter.html.erb @@ -0,0 +1,36 @@ +<% filter_label = defined?(search_type) && search_type == Search::PARAM_BAND ? :band : :musician %> +<%= content_tag(:div, :style => "min-width:770px;") do -%> + <%= content_tag(:div, :class => 'filter-element') do -%> + <%= content_tag(:div, 'Filter By:', :class => 'filter-element', :style => "padding-top:3px;") %> + + <%= select_tag("#{filter_label}_order_by", options_for_select(Search::ORDERINGS), {:class => "#{filter_label}-order-by"} ) %> + <% end -%> + <%= content_tag(:div, :class => 'filter-element') do -%> + <% if :musician == filter_label %> + + <%= content_tag(:div, 'Instrument:', :class => 'filter-element') %> + <%= content_tag(:div, :class => 'filter-element') do -%> + <%= select_tag("#{filter_label}_instrument", + options_for_select([['Any', '']].concat(JamRuby::Instrument.all.collect { |ii| [ii.description, ii.id] }))) %> + <% end -%> + <% elsif :band == filter_label %> + + <%= content_tag(:div, 'Genre:', :class => 'filter-element') %> + <%= content_tag(:div, :class => 'filter-element') do -%> + <%= select_tag("#{filter_label}_genre", + options_for_select([['Any', '']].concat(JamRuby::Genre.all.collect { |ii| [ii.description, ii.id] }))) %> + <% end -%> + <% end %> + <% end -%> + + <%= content_tag(:div, :class => 'filter-element') do -%> + <%= content_tag(:div, 'Within', :class => 'filter-element') %> + <%= content_tag(:div, :class => 'query-distance-params') do -%> + <% default_distance = :musician == filter_label ? Search::M_MILES_DEFAULT : Search::B_MILES_DEFAULT %> + <%= select_tag("#{filter_label}_query_distance", options_for_select(Search::DISTANCE_OPTS, default_distance)) %> + <% end -%> + <%= content_tag(:div, :class => 'filter-element') do -%> + miles of <%= content_tag(:span, current_user.current_city(request.remote_ip), :id => "#{filter_label}-filter-city") %> + <% end -%> + <% end -%> +<% end -%> From 380e264a9ae758d529bf30bef13e37c74ce284d2 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 9 Dec 2013 11:41:35 -0600 Subject: [PATCH 08/40] vrfs-884: got band filter specs to work --- ruby/lib/jam_ruby/models/band.rb | 3 +++ ruby/lib/jam_ruby/models/search.rb | 36 +++++++++++++++--------------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band.rb b/ruby/lib/jam_ruby/models/band.rb index 97200e21a..34ea63198 100644 --- a/ruby/lib/jam_ruby/models/band.rb +++ b/ruby/lib/jam_ruby/models/band.rb @@ -36,6 +36,9 @@ module JamRuby has_many :music_sessions, :class_name => "JamRuby::MusicSession", :foreign_key => "band_id" has_many :music_session_history, :class_name => "JamRuby::MusicSessionHistory", :foreign_key => "band_id", :inverse_of => :band + include Geokit::ActsAsMappable::Glue unless defined?(acts_as_mappable) + acts_as_mappable + def liker_count return self.likers.size end diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb index 3ab843f4a..dc68d1350 100644 --- a/ruby/lib/jam_ruby/models/search.rb +++ b/ruby/lib/jam_ruby/models/search.rb @@ -133,9 +133,7 @@ module JamRuby end rel = rel.select(sel_str) - perpage = [(params[:per_page] || M_PER_PAGE).to_i, 100].min - page = [params[:page].to_i, 1].max - rel = rel.paginate(:page => page, :per_page => perpage) + rel, page = self.relation_pagination(rel, params) rel = rel.includes([:instruments, :followings, :friends]) objs = rel.all @@ -144,6 +142,12 @@ module JamRuby srch.musician_results_for_user(objs, current_user) end + def self.relation_pagination(rel, params) + perpage = [(params[:per_page] || M_PER_PAGE).to_i, 100].min + page = [params[:page].to_i, 1].max + [rel.paginate(:page => page, :per_page => perpage), page] + end + RESULT_FOLLOW = :follows RESULT_FRIEND = :friends @@ -243,10 +247,9 @@ module JamRuby def self.band_search(params={}, current_user=nil) rel = Band.scoped - # rel = Arel::Table.new(:bands) unless (genre = params[:genre]).blank? - rel = Band.joins("RIGHT JOIN band_genres AS bgenres ON bgenres.band_id = bands.id") + rel = Band.joins("RIGHT JOIN bands_genres AS bgenres ON bgenres.band_id = bands.id") .where(['bgenres.genre_id = ? AND bands.id IS NOT NULL', genre]) end @@ -256,26 +259,23 @@ module JamRuby case ordering = self.order_param(params) when :plays # FIXME: double counting? sel_str = "COUNT(records)+COUNT(sessions) AS play_count, #{sel_str}" - rel = rel.joins("LEFT JOIN music_sessions AS sessions ON sessions.user_id = users.id") - .joins("LEFT JOIN recordings AS records ON records.owner_id = users.id") - .group("users.id") - .order("play_count DESC, users.created_at DESC") + rel = rel.joins("LEFT JOIN music_sessions AS sessions ON sessions.band_id = bands.id") + .joins("LEFT JOIN recordings AS records ON records.band_id = bands.id") + .group("bands.id") + .order("play_count DESC, bands.created_at DESC") when :followed sel_str = "COUNT(follows) AS search_follow_count, #{sel_str}" rel = rel.joins("LEFT JOIN bands_followers AS follows ON follows.band_id = bands.id") .group("bands.id") .order("COUNT(follows) DESC, bands.created_at DESC") when :playing - rel = rel.joins("LEFT JOIN connections ON connections.user_id = users.id") - .where(['connections.music_session_id IS NOT NULL AND connections.aasm_state != ?', - 'expired']) - .order("users.created_at DESC") + rel = rel.joins("LEFT JOIN music_sessions_history AS msh ON msh.band_id = bands.id") + .where('msh.music_session_id IS NOT NULL AND msh.session_removed_at IS NULL') + .order("bands.created_at DESC") end rel = rel.select(sel_str) - perpage = [(params[:per_page] || M_PER_PAGE).to_i, 100].min - page = [params[:page].to_i, 1].max - rel = rel.paginate(:page => page, :per_page => perpage) + rel, page = self.relation_pagination(rel, params) rel = rel.includes([:users]) objs = rel.all @@ -294,8 +294,8 @@ module JamRuby results.each do |bb| counters = { } counters[COUNT_FOLLOW] = BandFollowing.where(:band_id => bb.id).count - # counters[COUNT_RECORD] = ClaimedRecording.where(:band_id => bb.id).count - # counters[COUNT_SESSION] = MusicSession.where(:band_id => bb.id).count + counters[COUNT_RECORD] = Recording.where(:band_id => bb.id).count + counters[COUNT_SESSION] = MusicSession.where(:band_id => bb.id).count @user_counters[bb.id] << counters end From 2a93ce7caf4e25c028b7e08ea2fd1e035c6da570 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 9 Dec 2013 13:54:02 -0600 Subject: [PATCH 09/40] vrfs-884: refactored search filter var names --- ruby/lib/jam_ruby/models/search.rb | 15 +- .../models/band_filter_search_spec.rb | 149 +++++++----------- .../jam_ruby/models/musician_search_spec.rb | 40 ++--- web/app/views/api_search/index.rabl | 20 ++- 4 files changed, 105 insertions(+), 119 deletions(-) diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb index dc68d1350..62d5ca8f1 100644 --- a/ruby/lib/jam_ruby/models/search.rb +++ b/ruby/lib/jam_ruby/models/search.rb @@ -2,6 +2,7 @@ module JamRuby # not a active_record model; just a search result class Search attr_accessor :bands, :musicians, :fans, :recordings, :friends, :search_type + attr_accessor :bands_filter, :musicians_filter LIMIT = 10 # performs a site-white search @@ -30,6 +31,8 @@ module JamRuby @fans = [] @recordings = [] @friends = [] + @musicians_filter = [] + @bands_filter = [] if search_results.nil? return @@ -38,7 +41,7 @@ module JamRuby search_results.take(LIMIT).each do |result| if result.class == User if result.musician - @musicians.push(result) + @musicians_filter.push(result) @search_type = PARAM_MUSICIAN else @fans.push(result) @@ -158,10 +161,10 @@ module JamRuby COUNTERS = [COUNT_FRIEND, COUNT_FOLLOW, COUNT_RECORD, COUNT_SESSION] def musician_results_for_user(results, user) - @search_type, @musicians = PARAM_MUSICIAN, results + @search_type, @musicians_filter = PARAM_MUSICIAN, results if user @user_counters = results.inject({}) { |hh,val| hh[val.id] = []; hh } - mids = "'#{@musicians.map(&:id).join("','")}'" + mids = "'#{@musicians_filter.map(&:id).join("','")}'" # this gets counts for each search result on friends/follows/records/sessions results.each do |uu| @@ -276,7 +279,7 @@ module JamRuby rel = rel.select(sel_str) rel, page = self.relation_pagination(rel, params) - rel = rel.includes([:users]) + rel = rel.includes([{ :users => :instruments } ]) objs = rel.all srch = Search.new @@ -285,10 +288,10 @@ module JamRuby end def band_results_for_user(results, user) - @search_type, @bands = PARAM_BAND, results + @search_type, @bands_filter = PARAM_BAND, results if user @user_counters = results.inject({}) { |hh,val| hh[val.id] = []; hh } - mids = "'#{@bands.map(&:id).join("','")}'" + mids = "'#{@bands_filter.map(&:id).join("','")}'" # this gets counts for each search result results.each do |bb| diff --git a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb index b487890bb..51e43f403 100644 --- a/ruby/spec/jam_ruby/models/band_filter_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_filter_search_spec.rb @@ -26,23 +26,21 @@ describe 'Band search' do # expects all the bands num = Band.count results = Search.band_search({ :per_page => num }) - expect(results.bands.count).to eq(num) + expect(results.bands_filter.count).to eq(num) end it "finds bands with proper ordering" do # the ordering should be create_at since no followers exist expect(BandFollower.count).to eq(0) results = Search.band_search({ :per_page => Band.count }) - results.bands.each_with_index do |uu, idx| + results.bands_filter.each_with_index do |uu, idx| expect(uu.id).to eq(@bands.reverse[idx].id) end end it "sorts bands by followers" do users = [] - 4.downto(1) do |nn| - users << FactoryGirl.create(:user) - end + 4.downto(1) { |nn| users << FactoryGirl.create(:user) } # establish sorting order @band4.followers.concat(users[1..-1]) @@ -56,75 +54,51 @@ describe 'Band search' do # refresh the order to ensure it works right @band2.followers.concat(users[1..-1]) results = Search.band_search({ :per_page => @bands.size }, users[0]) - expect(results.bands[0].id).to eq(@band2.id) + expect(results.bands_filter[0].id).to eq(@band2.id) # check the follower count for given entry - expect(results.bands[0].search_follow_count.to_i).not_to eq(0) + expect(results.bands_filter[0].search_follow_count.to_i).not_to eq(0) # check the follow relationship between current_user and result expect(results.is_follower?(@band2)).to be true end it 'paginates properly' do - pending # make sure pagination works right params = { :per_page => 2, :page => 1 } results = Search.band_search(params) - expect(results.bands.count).to be 2 + expect(results.bands_filter.count).to be 2 end end - def make_recording(usr) - connection = FactoryGirl.create(:connection, :band => usr) - instrument = FactoryGirl.create(:instrument, :description => 'a great instrument') - track = FactoryGirl.create(:track, :connection => connection, :instrument => instrument) - music_session = FactoryGirl.create(:music_session, :creator => usr, :band_access => true) - music_session.connections << connection - music_session.save - recording = Recording.start(music_session, usr) - recording.stop - recording.reload - genre = FactoryGirl.create(:genre) - recording.claim(usr, "name", "description", genre, true, true) - recording.reload - recording + def make_session(band) + usr = band.users[0] + session = FactoryGirl.create(:music_session, :creator => usr, :description => "Session", :band => band) + FactoryGirl.create(:connection, :user => usr, :music_session => session) + user = FactoryGirl.create(:user) + session end - def make_session(usr) - connection = FactoryGirl.create(:connection, :band => usr) - music_session = FactoryGirl.create(:music_session, :creator => usr, :band_access => true) - music_session.connections << connection - music_session.save - end - -=begin context 'band stat counters' do - it "displays bands top followings" do - pending - @band4.followers.concat([@band4]) - @band3.followers.concat([@band4]) - @band2.followers.concat([@band4]) - expect(@band4.top_followings.count).to be 3 - expect(@band4.top_followings.map(&:id)).to match_array((@bands - [@band1]).map(&:id)) + it "follow stat shows follower count" do + users = [] + 2.downto(1) { |nn| users << FactoryGirl.create(:user) } + + # establish sorting order + @band1.followers.concat(users) + results = Search.band_search({},@band1) + uu = results.bands_filter.detect { |mm| mm.id == @band1.id } + expect(uu).to_not be_nil + expect(results.follow_count(uu)).to eq(users.count) end - it "recording stat shows recording count" do - pending - recording = make_recording(@band1) - expect(recording.bands.length).to be 1 - expect(recording.bands.first).to eq(@band1) + it "session stat shows session count" do + make_session(@band1) @band1.reload - expect(@band1.recordings.length).to be 1 - expect(@band1.recordings.first).to eq(recording) - expect(recording.claimed_recordings.length).to be 1 - expect(@band1.recordings.detect { |rr| rr == recording }).to_not be_nil - results = Search.band_search({},@band1) - uu = results.bands.detect { |mm| mm.id == @band1.id } + uu = results.bands_filter.detect { |mm| mm.id == @band1.id } expect(uu).to_not be_nil - - expect(results.record_count(uu)).to be 1 expect(results.session_count(uu)).to be 1 end @@ -133,86 +107,81 @@ describe 'Band search' do context 'band sorting' do it "by plays" do - pending - make_recording(@band1) + make_session(@band2) + make_session(@band2) + make_session(@band2) + make_session(@band1) # order results by num recordings - results = Search.band_search({ :orderby => 'plays' }, @band2) - expect(results.bands[0].id).to eq(@band1.id) - - # add more data and make sure order still correct - make_recording(@band2); make_recording(@band2) - results = Search.band_search({ :orderby => 'plays' }, @band2) - expect(results.bands[0].id).to eq(@band2.id) + results = Search.band_search({ :orderby => 'plays' }) + expect(results.bands_filter[0].id).to eq(@band2.id) + expect(results.bands_filter[1].id).to eq(@band1.id) end it "by now playing" do - pending # should get 1 result with 1 active session - make_session(@band3) - results = Search.band_search({ :orderby => 'playing' }, @band2) - expect(results.bands.count).to be 1 - expect(results.bands.first.id).to eq(@band3.id) + session = make_session(@band3) + FactoryGirl.create(:music_session_history, :music_session => session) + + results = Search.band_search({ :orderby => 'playing' }) + expect(results.bands_filter.count).to be 1 + expect(results.bands_filter.first.id).to eq(@band3.id) # should get 2 results with 2 active sessions # sort order should be created_at DESC - make_session(@band4) - results = Search.band_search({ :orderby => 'playing' }, @band2) - expect(results.bands.count).to be 2 - expect(results.bands[0].id).to eq(@band4.id) - expect(results.bands[1].id).to eq(@band3.id) + session = make_session(@band4) + FactoryGirl.create(:music_session_history, :music_session => session) + results = Search.band_search({ :orderby => 'playing' }) + expect(results.bands_filter.count).to be 2 + expect(results.bands_filter[0].id).to eq(@band4.id) + expect(results.bands_filter[1].id).to eq(@band3.id) end end + context 'filter settings' do - it "searches musicisns for an instrument" do - pending - minst = FactoryGirl.create(:band_instrument, { - :band => @band1, - :instrument => Instrument.find('tuba') }) - @band1.band_instruments << minst + it "searches bands for a genre" do + genre = FactoryGirl.create(:genre) + @band1.genres << genre @band1.reload - ii = @band1.instruments.detect { |inst| inst.id == 'tuba' } - expect(ii).to_not be_nil - results = Search.band_search({ :instrument => ii.id }) - results.bands.each do |rr| - expect(rr.instruments.detect { |inst| inst.id=='tuba' }.id).to eq(ii.id) + ggg = @band1.genres.detect { |gg| gg.id == genre.id } + expect(ggg).to_not be_nil + results = Search.band_search({ :genre => ggg.id }) + results.bands_filter.each do |rr| + expect(rr.genres.detect { |gg| gg.id==ggg.id }.id).to eq(genre.id) end - expect(results.count).to be 1 + expect(results.bands_filter.count).to be 1 end it "finds bands within a given distance of given location" do - pending num = Band.count expect(@band1.lat).to_not be_nil # short distance results = Search.band_search({ :per_page => num, :distance => 10, :city => 'Apex' }, @band1) - expect(results.count).to be num + expect(results.bands_filter.count).to be num # long distance results = Search.band_search({ :per_page => num, :distance => 1000, :city => 'Miami', :state => 'FL' }, @band1) - expect(results.count).to be num + expect(results.bands_filter.count).to be num end it "finds bands within a given distance of bands location" do - pending expect(@band1.lat).to_not be_nil # uses the location of @band1 results = Search.band_search({ :distance => 10, :per_page => Band.count }, @band1) - expect(results.count).to be Band.count + expect(results.bands_filter.count).to be Band.count end it "finds no bands within a given distance of location" do - pending expect(@band1.lat).to_not be_nil results = Search.band_search({ :distance => 10, :city => 'San Francisco' }, @band1) - expect(results.count).to be 0 + expect(results.bands_filter.count).to be 0 end end -=end + end diff --git a/ruby/spec/jam_ruby/models/musician_search_spec.rb b/ruby/spec/jam_ruby/models/musician_search_spec.rb index 6eda4ae28..955b2f04f 100644 --- a/ruby/spec/jam_ruby/models/musician_search_spec.rb +++ b/ruby/spec/jam_ruby/models/musician_search_spec.rb @@ -18,14 +18,14 @@ describe 'Musician search' do # expects all the users num = User.musicians.count results = Search.musician_search({ :per_page => num }) - expect(results.musicians.count).to eq(num) + expect(results.musicians_filter.count).to eq(num) end it "finds musicians with proper ordering" do # the ordering should be create_at since no followers exist expect(UserFollower.count).to eq(0) results = Search.musician_search({ :per_page => User.musicians.count }) - results.musicians.each_with_index do |uu, idx| + results.musicians_filter.each_with_index do |uu, idx| expect(uu.id).to eq(@users.reverse[idx].id) end end @@ -41,10 +41,10 @@ describe 'Musician search' do # refresh the order to ensure it works right @user2.followers.concat([@user3, @user4, @user2]) results = Search.musician_search({ :per_page => @users.size }, @user3) - expect(results.musicians[0].id).to eq(@user2.id) + expect(results.musicians_filter[0].id).to eq(@user2.id) # check the follower count for given entry - expect(results.musicians[0].search_follow_count.to_i).not_to eq(0) + expect(results.musicians_filter[0].search_follow_count.to_i).not_to eq(0) # check the follow relationship between current_user and result expect(results.is_follower?(@user2)).to be true end @@ -53,7 +53,7 @@ describe 'Musician search' do # make sure pagination works right params = { :per_page => 2, :page => 1 } results = Search.musician_search(params) - expect(results.musicians.count).to be 2 + expect(results.musicians_filter.count).to be 2 end end @@ -96,7 +96,7 @@ describe 'Musician search' do Friendship.save(@user1.id, @user2.id) # search on user2 results = Search.musician_search({}, @user2) - friend = results.musicians.detect { |mm| mm.id == @user1.id } + friend = results.musicians_filter.detect { |mm| mm.id == @user1.id } expect(friend).to_not be_nil expect(results.friend_count(friend)).to be 1 @user1.reload @@ -115,7 +115,7 @@ describe 'Musician search' do expect(@user1.recordings.detect { |rr| rr == recording }).to_not be_nil results = Search.musician_search({},@user1) - uu = results.musicians.detect { |mm| mm.id == @user1.id } + uu = results.musicians_filter.detect { |mm| mm.id == @user1.id } expect(uu).to_not be_nil expect(results.record_count(uu)).to be 1 @@ -130,28 +130,28 @@ describe 'Musician search' do make_recording(@user1) # order results by num recordings results = Search.musician_search({ :orderby => 'plays' }, @user2) - expect(results.musicians[0].id).to eq(@user1.id) + expect(results.musicians_filter[0].id).to eq(@user1.id) # add more data and make sure order still correct make_recording(@user2); make_recording(@user2) results = Search.musician_search({ :orderby => 'plays' }, @user2) - expect(results.musicians[0].id).to eq(@user2.id) + expect(results.musicians_filter[0].id).to eq(@user2.id) end it "by now playing" do # should get 1 result with 1 active session make_session(@user3) results = Search.musician_search({ :orderby => 'playing' }, @user2) - expect(results.musicians.count).to be 1 - expect(results.musicians.first.id).to eq(@user3.id) + expect(results.musicians_filter.count).to be 1 + expect(results.musicians_filter.first.id).to eq(@user3.id) # should get 2 results with 2 active sessions # sort order should be created_at DESC make_session(@user4) results = Search.musician_search({ :orderby => 'playing' }, @user2) - expect(results.musicians.count).to be 2 - expect(results.musicians[0].id).to eq(@user4.id) - expect(results.musicians[1].id).to eq(@user3.id) + expect(results.musicians_filter.count).to be 2 + expect(results.musicians_filter[0].id).to eq(@user4.id) + expect(results.musicians_filter[1].id).to eq(@user3.id) end end @@ -166,10 +166,10 @@ describe 'Musician search' do ii = @user1.instruments.detect { |inst| inst.id == 'tuba' } expect(ii).to_not be_nil results = Search.musician_search({ :instrument => ii.id }) - results.musicians.each do |rr| + results.musicians_filter.each do |rr| expect(rr.instruments.detect { |inst| inst.id=='tuba' }.id).to eq(ii.id) end - expect(results.musicians.count).to be 1 + expect(results.musicians_filter.count).to be 1 end it "finds musicians within a given distance of given location" do @@ -179,26 +179,26 @@ describe 'Musician search' do results = Search.musician_search({ :per_page => num, :distance => 10, :city => 'Apex' }, @user1) - expect(results.musicians.count).to be num + expect(results.musicians_filter.count).to be num # long distance results = Search.musician_search({ :per_page => num, :distance => 1000, :city => 'Miami', :state => 'FL' }, @user1) - expect(results.musicians.count).to be num + expect(results.musicians_filter.count).to be num end it "finds musicians within a given distance of users location" do expect(@user1.lat).to_not be_nil # uses the location of @user1 results = Search.musician_search({ :distance => 10, :per_page => User.musicians.count }, @user1) - expect(results.musicians.count).to be User.musicians.count + expect(results.musicians_filter.count).to be User.musicians.count end it "finds no musicians within a given distance of location" do expect(@user1.lat).to_not be_nil results = Search.musician_search({ :distance => 10, :city => 'San Francisco' }, @user1) - expect(results.musicians.count).to be 0 + expect(results.musicians_filter.count).to be 0 end end diff --git a/web/app/views/api_search/index.rabl b/web/app/views/api_search/index.rabl index f4ec6a6e8..4c66715b5 100644 --- a/web/app/views/api_search/index.rabl +++ b/web/app/views/api_search/index.rabl @@ -1,12 +1,26 @@ object @search -unless @search.bands.nil? || @search.bands.size == 0 +if @search.bands.present? child(:bands => :bands) { attributes :id, :name, :location, :photo_url, :logo_url } end -unless @search.musicians.nil? || @search.musicians.size == 0 +if @search.musicians.present? + child(:musicians => :musicians) { + attributes :id, :first_name, :last_name, :name, :location, :photo_url + + node :is_friend do |musician| + musician.friends?(current_user) + end + + child :musician_instruments => :instruments do + attributes :instrument_id, :description, :proficiency_level, :priority + end + } +end + +if @search.musicians_filter.present? node :city do |user| current_user.try(:location) @@ -16,7 +30,7 @@ unless @search.musicians.nil? || @search.musicians.size == 0 @search.page_count end - child(:musicians => :musicians) { + child(:musicians_filter => :musicians) { attributes :id, :first_name, :last_name, :name, :city, :state, :country, :email, :online, :musician, :photo_url, :biography node :is_friend do |musician| From 3968f4015a5b3d291306402bf4cce63d204de3af Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 9 Dec 2013 13:55:02 -0600 Subject: [PATCH 10/40] vrfs-884: added bands view layout --- web/app/views/clients/_bands.html.erb | 48 +++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/web/app/views/clients/_bands.html.erb b/web/app/views/clients/_bands.html.erb index 417f3446d..4da67b440 100644 --- a/web/app/views/clients/_bands.html.erb +++ b/web/app/views/clients/_bands.html.erb @@ -14,3 +14,51 @@ <% end -%> <% end -%> <% end -%> + + + + + + + + From 88f9339fe2d18a9ec24d256620846fed45944b8a Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 9 Dec 2013 13:55:18 -0600 Subject: [PATCH 11/40] vrfs-884: removed commented code --- web/app/assets/javascripts/findMusician.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/web/app/assets/javascripts/findMusician.js b/web/app/assets/javascripts/findMusician.js index 7288e28c0..7c1e2e93a 100644 --- a/web/app/assets/javascripts/findMusician.js +++ b/web/app/assets/javascripts/findMusician.js @@ -197,15 +197,6 @@ } function events() { - /* - $("#musician_query_distance").keypress(function(evt) { - if (evt.which === 13) { - evt.preventDefault(); - refreshDisplay(); - } - }); - $('#btn-refresh-musicians').on("click", refreshDisplay); - */ $('#musician_query_distance').change(refreshDisplay); $('#musician_instrument').change(refreshDisplay); $('#musician_order_by').change(refreshDisplay); From a30bc2a022ce671b79b7e4594db66b16eb5d537d Mon Sep 17 00:00:00 2001 From: Seth Call Date: Thu, 12 Dec 2013 14:57:54 +0000 Subject: [PATCH 12/40] * fix for VRFS-901 - when you remove a track there was a typo in the jamClient reference --- web/app/assets/javascripts/configureTrack.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/app/assets/javascripts/configureTrack.js b/web/app/assets/javascripts/configureTrack.js index 94feb2fc8..966804fcc 100644 --- a/web/app/assets/javascripts/configureTrack.js +++ b/web/app/assets/javascripts/configureTrack.js @@ -613,7 +613,7 @@ // track 2 was removed if (myTrackCount === 2) { logger.debug("Deleting track " + myTracks[1].trackId); - client.TrackSetCount(1); + context.jamClient.TrackSetCount(1); //sessionModel.deleteTrack(sessionId, myTracks[1].trackId); } } @@ -830,4 +830,4 @@ return this; }; - })(window,jQuery); \ No newline at end of file + })(window,jQuery); From fa8df410dab66faba94e018c0745bb484eebfade Mon Sep 17 00:00:00 2001 From: Chris Doughty Date: Thu, 12 Dec 2013 20:47:20 -0600 Subject: [PATCH 13/40] VRFS-719 Added code to force downloads through cloudfront --- web/app/controllers/artifacts_controller.rb | 3 ++- web/config/application.rb | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/web/app/controllers/artifacts_controller.rb b/web/app/controllers/artifacts_controller.rb index 45c74c832..180f12286 100644 --- a/web/app/controllers/artifacts_controller.rb +++ b/web/app/controllers/artifacts_controller.rb @@ -51,11 +51,12 @@ class ArtifactsController < ApiController end def determine_url(artifact) + if SampleApp::Application.config.storage_type == :file # this is basically a dev-time only path of code; we store real artifacts in s3 url = SampleApp::Application.config.jam_admin_root_url + artifact.uri.url else - url = artifact.uri.url + url = artifact.uri.url.gsub(SampleApp::Application.config.aws_fullhost,SampleApp::Application.config.cloudfront_host) end return url diff --git a/web/config/application.rb b/web/config/application.rb index 03afc6ec8..606adebb8 100644 --- a/web/config/application.rb +++ b/web/config/application.rb @@ -122,6 +122,10 @@ if defined?(Bundler) config.aws_bucket = 'jamkazam-dev' config.aws_bucket_public = 'jamkazam-dev-public' config.aws_cache = '315576000' + config.aws_fullhost = "#{config.aws_bucket_public}.s3.amazonaws.com" + + # cloudfront host + config.cloudfront_host = "d34f55ppvvtgi3.cloudfront.net" # facebook keys config.facebook_key = '468555793186398' From b5efad954d87edb22519a468c733b3c045218630 Mon Sep 17 00:00:00 2001 From: Chris Doughty Date: Sat, 14 Dec 2013 13:07:38 -0600 Subject: [PATCH 14/40] Adding prd and dev cloudfront hosts --- web/config/environments/development.rb | 3 +++ web/config/environments/production.rb | 3 +++ 2 files changed, 6 insertions(+) diff --git a/web/config/environments/development.rb b/web/config/environments/development.rb index 35f492750..025879ad0 100644 --- a/web/config/environments/development.rb +++ b/web/config/environments/development.rb @@ -45,6 +45,9 @@ SampleApp::Application.configure do TEST_CONNECT_STATES = false + # Overloaded value to match production for using cloudfront in dev mode + config.cloudfront_host = "d2bc92otq4j4dd.cloudfront.net" + # this is totally awful and silly; the reason this exists is so that if you upload an artifact # through jam-admin, then jam-web can point users at it. I think 99% of devs won't even see or care about this config, and 0% of users config.jam_admin_root_url = 'http://192.168.1.152:3333' diff --git a/web/config/environments/production.rb b/web/config/environments/production.rb index f4328abb5..3a8848354 100644 --- a/web/config/environments/production.rb +++ b/web/config/environments/production.rb @@ -77,6 +77,9 @@ SampleApp::Application.configure do config.aws_bucket = 'jamkazam' config.aws_bucket_public = 'jamkazam-public' + # Dev cloudfront hostname + config.cloudfront_host = "d34f55ppvvtgi3.cloudfront.net" + # filepicker app configured to use S3 bucket jamkazam config.filepicker_rails.api_key = "AhUoVoBZSLirP3esyCl7Zz" config.fp_secret = 'HZBIMSOI5VAQ5LXT4XLG6XA7IE' From 4e273759babfbef38a2d8fd39f360efc7fa77715 Mon Sep 17 00:00:00 2001 From: Anthony Davis Date: Sat, 14 Dec 2013 17:53:18 -0600 Subject: [PATCH 15/40] adding: bands_spec, link ids, more in_session JS testing and refactoring --- web/app/views/clients/_profile.html.erb | 4 +- web/spec/features/in_session_spec.rb | 48 +++++++++++++++---- web/spec/features/recordings_spec.rb | 2 +- web/spec/support/utilities.rb | 62 +++++++++++++++++++------ 4 files changed, 91 insertions(+), 25 deletions(-) diff --git a/web/app/views/clients/_profile.html.erb b/web/app/views/clients/_profile.html.erb index ff822567b..002a4add9 100644 --- a/web/app/views/clients/_profile.html.erb +++ b/web/app/views/clients/_profile.html.erb @@ -96,13 +96,13 @@ diff --git a/web/spec/features/in_session_spec.rb b/web/spec/features/in_session_spec.rb index 5d8a1ee38..709777af8 100644 --- a/web/spec/features/in_session_spec.rb +++ b/web/spec/features/in_session_spec.rb @@ -21,14 +21,17 @@ describe "In a Session", :js => true, :type => :feature, :capybara_feature => tr it "can't see a private session until it is made public", :slow => true do create_session(user, description = "Public or private, I cant decide!") - set_session_as_private(user) + in_client(user) do + set_session_as_private + end in_client(finder) do sign_in_poltergeist finder visit "/client#/findSession" expect(page).to have_selector('#sessions-none-found') # verify private session is not found end - - set_session_as_public(user) + in_client(user) do + set_session_as_public + end join_session(finder, description) # verify the public session is able to be joined end @@ -57,11 +60,38 @@ describe "In a Session", :js => true, :type => :feature, :capybara_feature => tr in_client(finder) { expect(page).to_not have_selector('div.track-label', text: user.name) } end - #it "can see all tracks with four users", :slow => true do - # others = Array.new - # 3.times { others.push FactoryGirl.create(:user) } - # create_join_session(user, others) - # assert_all_tracks_seen(others.push user) - #end + many = 4 + + it "can see all tracks with #{many} users in a session", :slow => true do + others = Array.new + (many-1).times { others.push FactoryGirl.create(:user) } + create_join_session(user, others) + assert_all_tracks_seen(others.push user) + #in_client(others[0]) {page.save_screenshot('tmp/partys_all_here_now.png')} + end + + it "a user can change the genre and the change will be seen by another participant" do + pending "...it doesn't work this way, but i will reuse this pattern" + create_join_session(user, [finder]) + in_client(user) do + @new_genre = change_session_genre + end + in_client(finder) do + expect(get_session_genre).to include(@new_genre) + end + end + + it "a user can change the genre and the Find Session screen will be updated" do + create_session(user) + in_client(finder) { sign_in_poltergeist finder } + 2.times do + in_client(user) do + @new_genre = change_session_genre #randomizes it + end + in_client(finder) do + find_session_contains?(@new_genre) + end + end + end end diff --git a/web/spec/features/recordings_spec.rb b/web/spec/features/recordings_spec.rb index dda0de29d..b37891118 100644 --- a/web/spec/features/recordings_spec.rb +++ b/web/spec/features/recordings_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Find Session", :js => true, :type => :feature, :capybara_feature => true, :slow => true do +describe "Session Recordings", :js => true, :type => :feature, :capybara_feature => true, :slow => true do subject { page } diff --git a/web/spec/support/utilities.rb b/web/spec/support/utilities.rb index 7c8134e78..38e2467e3 100644 --- a/web/spec/support/utilities.rb +++ b/web/spec/support/utilities.rb @@ -125,7 +125,7 @@ end # this code assumes that there are no music sessions in the database. it should fail on the -# find('.join-link') call if > 1 session exists because capybara will complain of multile matches +# find('.join-link') call if > 1 session exists because capybara will complain of multiple matches def join_session(joiner, unique_session_desc) in_client(joiner) do @@ -141,6 +141,7 @@ def join_session(joiner, unique_session_desc) end end + def create_join_session(creator, joiners=[]) creator, unique_session_desc = create_session(creator) @@ -151,26 +152,61 @@ def create_join_session(creator, joiners=[]) end -def set_session_as_private(session_owner) - in_client(session_owner) do - find('#session-settings-button').trigger(:click) - within('#session-settings-dialog') do +def set_session_as_private() + find('#session-settings-button').trigger(:click) + within('#session-settings-dialog') do select('Private', :from => 'session-settings-musician-access') find('#session-settings-dialog-submit').trigger(:click) - end end end -def set_session_as_public(session_owner) - in_client(session_owner) do - find('#session-settings-button').trigger(:click) - within('#session-settings-dialog') do - select('Public', :from => 'session-settings-musician-access') - find('#session-settings-dialog-submit').trigger(:click) - end +def set_session_as_public() + find('#session-settings-button').trigger(:click) + within('#session-settings-dialog') do + select('Public', :from => 'session-settings-musician-access') + find('#session-settings-dialog-submit').trigger(:click) end end +def get_options(selector) + return find(selector).all('option').collect(&:text).uniq +end + +def selected_genres + return page.evaluate_script("JK.GenreSelectorHelper.getSelectedGenres('#session-settings-genre')") +end + +def change_session_genre #randomly just change it + here = 'select.genre-list' + #wait_for_ajax + find('#session-settings-button').trigger(:click) + within('#session-settings-dialog') do + wait_for_ajax + @new_genre = get_options(here).-(["Select Genre"]).-(selected_genres).sample.to_s + select(@new_genre, :from => 'genres') + wait_for_ajax + find('#session-settings-dialog-submit').trigger(:click) + end + return @new_genre +end + +def get_session_genre + here = 'select.genre-list' + find('#session-settings-button').trigger(:click) + wait_for_ajax + @current_genres = selected_genres + find('#session-settings-dialog-submit').trigger(:click) + return @current_genres.join(" ") +end + +def find_session_contains?(text) + visit "/client#/findSession" + wait_for_ajax + within('#find-session-form') do + expect(page).to have_text(text) + end +end + def assert_all_tracks_seen(users=[]) users.each do |user| in_client(user) do From 9de0d84106fb0bd57b094d0597e013a06fb384ae Mon Sep 17 00:00:00 2001 From: Anthony Davis Date: Sat, 14 Dec 2013 17:59:48 -0600 Subject: [PATCH 16/40] adding: bands_spec (oops, was not git added) --- web/spec/features/bands_spec.rb | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 web/spec/features/bands_spec.rb diff --git a/web/spec/features/bands_spec.rb b/web/spec/features/bands_spec.rb new file mode 100644 index 000000000..898df6a02 --- /dev/null +++ b/web/spec/features/bands_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +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 + end + + let(:user) { FactoryGirl.create(:user) } + let(:finder) { FactoryGirl.create(:user) } + + before(:each) do + UserMailer.deliveries.clear + end + + it "band setup is accessible through profile page" do + sign_in_poltergeist(user) + wait_until_curtain_gone + find('div.homecard.profile').trigger(:click) + wait_for_ajax + find('#profile-bands-link').trigger(:click) + wait_for_ajax + find('#band-setup-link').trigger(:click) + expect(page).to have_selector('#band-setup-title') + end + +end + + From 5b5aef15c8c05bce939fb84c95aeac2ab36e6794 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Sun, 15 Dec 2013 16:27:11 -0500 Subject: [PATCH 17/40] VRFS-877 band photo work --- db/manifest | 3 +- ruby/lib/jam_ruby/models/band.rb | 36 ++ .../javascripts/accounts_profile_avatar.js | 3 +- web/app/assets/javascripts/band_setup.js | 14 +- .../assets/javascripts/band_setup_photo.js | 431 ++++++++++++++++++ web/app/assets/javascripts/jam_rest.js | 51 +++ .../assets/stylesheets/client/band.css.scss | 37 ++ web/app/controllers/api_bands_controller.rb | 53 ++- web/app/views/api_bands/show.rabl | 3 +- .../views/clients/_account_profile.html.erb | 2 +- .../clients/_account_profile_avatar.html.erb | 4 +- web/app/views/clients/_band_setup.html.erb | 2 +- .../views/clients/_band_setup_photo.html.erb | 41 ++ web/app/views/clients/index.html.erb | 4 + web/config/routes.rb | 5 + 15 files changed, 679 insertions(+), 10 deletions(-) create mode 100644 web/app/assets/javascripts/band_setup_photo.js create mode 100644 web/app/views/clients/_band_setup_photo.html.erb 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/ruby/lib/jam_ruby/models/band.rb b/ruby/lib/jam_ruby/models/band.rb index 5f47cdb9d..4589d20cd 100644 --- a/ruby/lib/jam_ruby/models/band.rb +++ b/ruby/lib/jam_ruby/models/band.rb @@ -3,6 +3,8 @@ module JamRuby attr_accessible :name, :website, :biography, :city, :state, :country + attr_accessor :updating_photo + self.primary_key = 'id' validates :biography, no_profanity: true @@ -187,6 +189,40 @@ module JamRuby return band end + def update_avatar(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_avatar(aws_bucket) + + User.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? diff --git a/web/app/assets/javascripts/accounts_profile_avatar.js b/web/app/assets/javascripts/accounts_profile_avatar.js index 48bbfc20d..460a6ab8b 100644 --- a/web/app/assets/javascripts/accounts_profile_avatar.js +++ b/web/app/assets/javascripts/accounts_profile_avatar.js @@ -18,6 +18,7 @@ var userDropdown; function beforeShow(data) { + logger.debug("data.id=" + data.id); userId = data.id; } @@ -150,7 +151,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..eb1d30316 100644 --- a/web/app/assets/javascripts/band_setup.js +++ b/web/app/assets/javascripts/band_setup.js @@ -229,7 +229,7 @@ userNames = []; userIds = []; userPhotoUrls = []; - bandId = $("#hdn-band-id").val(); + bandId = "1158c8b6-4c92-47dc-82bf-1e390c4f9b2c";// $("#hdn-band-id").val(); resetForm(); } @@ -259,6 +259,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.'); } } @@ -271,7 +274,7 @@ loadGenres(band.genres); loadCountries(band.country, function() { - loadRegions(band.region, function() { + loadRegions(band.state, function() { loadCities(band.city); }); }); @@ -492,6 +495,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..af00f42c0 --- /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(); handleDeletePhoto(); 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(); handleUpdatePhoto(); 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..f36dfddc4 100644 --- a/web/app/assets/javascripts/jam_rest.js +++ b/web/app/assets/javascripts/jam_rest.js @@ -252,6 +252,54 @@ }); } + 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']; + + 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 +547,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 @@ - +
diff --git a/web/app/views/clients/_account_profile_avatar.html.erb b/web/app/views/clients/_account_profile_avatar.html.erb index 57ff42942..49bf17f20 100644 --- a/web/app/views/clients/_account_profile_avatar.html.erb +++ b/web/app/views/clients/_account_profile_avatar.html.erb @@ -1,4 +1,4 @@ - +
@@ -35,7 +35,7 @@
- + diff --git a/web/app/views/clients/_band_setup.html.erb b/web/app/views/clients/_band_setup.html.erb index fcacd7aac..ab8e9e77a 100644 --- a/web/app/views/clients/_band_setup.html.erb +++ b/web/app/views/clients/_band_setup.html.erb @@ -25,7 +25,7 @@ <%= image_tag "shared/avatar_generic_band.png", {:id => "band-avatar", :align=>"absmiddle", :height => 88, :width => 88 } %>

- Upload Band Photo

+ Upload Band Photo

diff --git a/web/app/views/clients/_band_setup_photo.html.erb b/web/app/views/clients/_band_setup_photo.html.erb new file mode 100644 index 000000000..986821592 --- /dev/null +++ b/web/app/views/clients/_band_setup_photo.html.erb @@ -0,0 +1,41 @@ + +
+ +
+ +
+ <%= image_tag "content/icon_bands.png", {:width => 19, :height => 19} %> +
+ +

band setup

+ <%= render "screen_navigation" %> +
+ + + +
+ +
+ +
+ + \ No newline at end of file diff --git a/web/app/views/clients/index.html.erb b/web/app/views/clients/index.html.erb index 6985978e4..c8e8300a8 100644 --- a/web/app/views/clients/index.html.erb +++ b/web/app/views/clients/index.html.erb @@ -22,6 +22,7 @@ <%= render "profile" %> <%= render "bandProfile" %> <%= render "band_setup" %> +<%= render "band_setup_photo" %> <%= render "feed" %> <%= render "bands" %> <%= render "musicians" %> @@ -141,6 +142,9 @@ var bandSetupScreen = new JK.BandSetupScreen(JK.app); bandSetupScreen.initialize(invitationDialog, friendSelectorDialog); + var bandSetupPhotoScreen = new JK.BandSetupPhotoScreen(JK.app); + bandSetupPhotoScreen.initialize(); + var findSessionScreen = new JK.FindSessionScreen(JK.app); var sessionLatency = null; if ("jamClient" in window) { diff --git a/web/config/routes.rb b/web/config/routes.rb index 6e7974b7f..c738c10f5 100644 --- a/web/config/routes.rb +++ b/web/config/routes.rb @@ -204,6 +204,11 @@ SampleApp::Application.routes.draw do match '/bands' => 'api_bands#create', :via => :post match '/bands/:id' => 'api_bands#update', :via => :post + # photo + match '/bands/:id/photo' => 'api_bands#update_photo', :via => :post + match '/bands/:id/photo' => 'api_bands#delete_photo', :via => :delete + match '/bands/:id/filepicker_policy' => 'api_bands#generate_filepicker_policy', :via => :get + # band members match '/bands/:id/musicians' => 'api_bands#musician_index', :via => :get match '/bands/:id/musicians' => 'api_bands#musician_create', :via => :post From 0aaa460934df644f027bc486b47eb73045ac549e Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Sun, 15 Dec 2013 16:30:04 -0500 Subject: [PATCH 18/40] VRFS-877 band photo work --- ruby/lib/jam_ruby/models/band.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band.rb b/ruby/lib/jam_ruby/models/band.rb index 4589d20cd..56161d067 100644 --- a/ruby/lib/jam_ruby/models/band.rb +++ b/ruby/lib/jam_ruby/models/band.rb @@ -189,7 +189,7 @@ module JamRuby return band end - def update_avatar(original_fpfile, cropped_fpfile, crop_selection, aws_bucket) + def update_photo(original_fpfile, cropped_fpfile, crop_selection, aws_bucket) self.updating_photo = true cropped_s3_path = cropped_fpfile["key"] @@ -203,9 +203,9 @@ module JamRuby ) end - def delete_avatar(aws_bucket) + def delete_photo(aws_bucket) - User.transaction do + Band.transaction do unless self.cropped_s3_path.nil? S3Util.delete(aws_bucket, File.dirname(self.cropped_s3_path) + '/cropped.jpg') From 5ea5fd3d638f38458352100330185cba1840b9b1 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Sun, 15 Dec 2013 20:26:21 -0500 Subject: [PATCH 19/40] VRFS-877 add missing sql file --- db/up/band_photo_filepicker.sql | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 db/up/band_photo_filepicker.sql 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 From d310484c3bd230ba3f0112099b6e5029a19515a1 Mon Sep 17 00:00:00 2001 From: Chris Doughty Date: Sun, 15 Dec 2013 20:01:13 -0600 Subject: [PATCH 20/40] VRFS-719 fixing error case where path is incorrectly built --- web/config/environments/production.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/web/config/environments/production.rb b/web/config/environments/production.rb index 3a8848354..61a091e10 100644 --- a/web/config/environments/production.rb +++ b/web/config/environments/production.rb @@ -76,6 +76,7 @@ SampleApp::Application.configure do config.aws_bucket = 'jamkazam' config.aws_bucket_public = 'jamkazam-public' + config.aws_fullhost = "#{config.aws_bucket_public}.s3.amazonaws.com" # Dev cloudfront hostname config.cloudfront_host = "d34f55ppvvtgi3.cloudfront.net" From d583393598e1d8a73db25846a493b52d577eafcd Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Sun, 15 Dec 2013 22:53:16 -0500 Subject: [PATCH 21/40] VRFS-877 bug fixes --- ruby/lib/jam_ruby/models/band.rb | 24 ++++++++++++++++++- .../javascripts/accounts_profile_avatar.js | 3 --- web/app/assets/javascripts/band_setup.js | 7 +++++- .../assets/javascripts/band_setup_photo.js | 4 ++-- web/app/assets/javascripts/jam_rest.js | 12 ++++++++++ web/app/views/clients/_session.html.erb | 1 - 6 files changed, 43 insertions(+), 8 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band.rb b/ruby/lib/jam_ruby/models/band.rb index 56161d067..640f6c2a0 100644 --- a/ruby/lib/jam_ruby/models/band.rb +++ b/ruby/lib/jam_ruby/models/band.rb @@ -1,12 +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 @@ -59,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 @@ -241,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 460a6ab8b..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,8 +17,6 @@ var userDropdown; function beforeShow(data) { - logger.debug("data.id=" + data.id); - userId = data.id; } diff --git a/web/app/assets/javascripts/band_setup.js b/web/app/assets/javascripts/band_setup.js index eb1d30316..5752a35e4 100644 --- a/web/app/assets/javascripts/band_setup.js +++ b/web/app/assets/javascripts/band_setup.js @@ -229,7 +229,8 @@ userNames = []; userIds = []; userPhotoUrls = []; - bandId = "1158c8b6-4c92-47dc-82bf-1e390c4f9b2c";// $("#hdn-band-id").val(); + //bandId = "1158c8b6-4c92-47dc-82bf-1e390c4f9b2c"; + bandId = $("#hdn-band-id").val(); resetForm(); } @@ -271,6 +272,10 @@ $("#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() { diff --git a/web/app/assets/javascripts/band_setup_photo.js b/web/app/assets/javascripts/band_setup_photo.js index af00f42c0..f5775cee5 100644 --- a/web/app/assets/javascripts/band_setup_photo.js +++ b/web/app/assets/javascripts/band_setup_photo.js @@ -60,9 +60,9 @@ 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(); handleDeletePhoto(); 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(); handleUpdatePhoto(); 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; } ); } diff --git a/web/app/assets/javascripts/jam_rest.js b/web/app/assets/javascripts/jam_rest.js index f36dfddc4..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", @@ -259,6 +265,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/bands/" + id + "/photo"; return $.ajax({ type: "POST", diff --git a/web/app/views/clients/_session.html.erb b/web/app/views/clients/_session.html.erb index eda192a6b..4c71c8349 100644 --- a/web/app/views/clients/_session.html.erb +++ b/web/app/views/clients/_session.html.erb @@ -5,7 +5,6 @@ <%= image_tag "shared/icon_session.png", {:height => 19, :width => 19} %>

session

- <%= render "screen_navigation" %>
From 836e786ebf48ecd1eada24063b6c530e88fc6f2c Mon Sep 17 00:00:00 2001 From: Chris Doughty Date: Mon, 16 Dec 2013 07:51:46 -0600 Subject: [PATCH 22/40] Correcting staging cloudfront distribution with correct s3 bucket --- web/config/environments/development.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/config/environments/development.rb b/web/config/environments/development.rb index 025879ad0..cbc4b11b9 100644 --- a/web/config/environments/development.rb +++ b/web/config/environments/development.rb @@ -46,7 +46,7 @@ SampleApp::Application.configure do TEST_CONNECT_STATES = false # Overloaded value to match production for using cloudfront in dev mode - config.cloudfront_host = "d2bc92otq4j4dd.cloudfront.net" + config.cloudfront_host = "d48bcgsnmsm6a.cloudfront.net" # this is totally awful and silly; the reason this exists is so that if you upload an artifact # through jam-admin, then jam-web can point users at it. I think 99% of devs won't even see or care about this config, and 0% of users From 65f3200fd7757d2c868018d23e1aaf6b99b790a9 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 16 Dec 2013 12:23:02 -0600 Subject: [PATCH 23/40] vrfs-884: added :genres eager loading --- ruby/lib/jam_ruby/models/search.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb index 62d5ca8f1..e3f200677 100644 --- a/ruby/lib/jam_ruby/models/search.rb +++ b/ruby/lib/jam_ruby/models/search.rb @@ -279,7 +279,7 @@ module JamRuby rel = rel.select(sel_str) rel, page = self.relation_pagination(rel, params) - rel = rel.includes([{ :users => :instruments } ]) + rel = rel.includes([{ :users => :instruments }, :genres ]) objs = rel.all srch = Search.new From a354f6c6d5a5f7a12ce753b82cc6d15babf846a0 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 16 Dec 2013 12:28:21 -0600 Subject: [PATCH 24/40] vrfs-884: updating sample data for bands --- web/lib/tasks/sample_data.rake | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/web/lib/tasks/sample_data.rake b/web/lib/tasks/sample_data.rake index cd8d77f07..dee36061d 100644 --- a/web/lib/tasks/sample_data.rake +++ b/web/lib/tasks/sample_data.rake @@ -14,6 +14,14 @@ namespace :db do make_friends end + task populate_bands: :environment do + make_bands + end + + task populate_band_members: :environment do + make_band_members + end + desc "Fill database with music session sample data" task populate_music_sessions: :environment do make_users(10) if 14 > User.count @@ -56,16 +64,24 @@ def make_music_sessions_user_history end end +def make_band_members + Band.find_each do |bb| + User.order('RANDOM()').limit(4).each do |uu| + BandMusician.create!({:user_id => uu.id, :band_id => bb.id}) + end + end +end + def make_bands 10.times do |nn| name = Faker::Name.name website = Faker::Internet.url biography = Faker::Lorem.sentence - city = Faker::Address.city - state = Faker::Address.state_abbr - country = Faker::Address.country + city = 'Austin' # Faker::Address.city + state = 'TX' # Faker::Address.state_abbr + country = 'US' - Band.create!( + bb = Band.new( name: name, website: website, biography: biography, @@ -73,6 +89,11 @@ def make_bands state: state, country: country, ) + begin + bb.save! + rescue + puts $!.to_s + ' ' + bb.errors.inspect + end end end From 9dd631d05a1d283b8bbb9b4d2d966cf1e7c01c51 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 16 Dec 2013 12:29:16 -0600 Subject: [PATCH 25/40] vrfs-884: added PARAM_BAND support --- web/app/controllers/api_search_controller.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/app/controllers/api_search_controller.rb b/web/app/controllers/api_search_controller.rb index 006b64783..63c0ff8d9 100644 --- a/web/app/controllers/api_search_controller.rb +++ b/web/app/controllers/api_search_controller.rb @@ -7,11 +7,15 @@ class ApiSearchController < ApiController def index if 1 == params[Search::PARAM_MUSICIAN].to_i - logger.debug("*** params = #{params.inspect}") query = params.clone query[:remote_ip] = request.remote_ip @search = Search.musician_search(query, current_user) respond_with @search, responder: ApiResponder, :status => 200 + elsif 1 == params[Search::PARAM_BAND].to_i + query = params.clone + query[:remote_ip] = request.remote_ip + @search = Search.band_search(query, current_user) + respond_with @search, responder: ApiResponder, :status => 200 else @search = Search.search(params[:query], current_user.id) end From fc6d12e9c8526ba0a6861af6af0e29a0569694f9 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 16 Dec 2013 12:31:12 -0600 Subject: [PATCH 26/40] vrfs-884: band filter page --- web/app/assets/javascripts/findBand.js | 228 +++++++++++++++++++++++++ web/app/views/api_search/index.rabl | 30 ++++ web/app/views/clients/_bands.html.erb | 19 +-- web/app/views/clients/index.html.erb | 3 + 4 files changed, 269 insertions(+), 11 deletions(-) create mode 100644 web/app/assets/javascripts/findBand.js diff --git a/web/app/assets/javascripts/findBand.js b/web/app/assets/javascripts/findBand.js new file mode 100644 index 000000000..a8a9714db --- /dev/null +++ b/web/app/assets/javascripts/findBand.js @@ -0,0 +1,228 @@ +(function(context,$) { + "use strict"; + + context.JK = context.JK || {}; + context.JK.FindBandScreen = function(app) { + + var logger = context.JK.logger; + var bands = {}; + var bandList; + var instrument_logo_map = context.JK.getInstrumentIconMap24(); + var did_show_band_page = false; + var page_num=1, page_count=0; + + function loadBands(queryString) { + // squelch nulls and undefines + queryString = !!queryString ? queryString : ""; + + $.ajax({ + type: "GET", + url: "/api/search.json?" + queryString, + async: true, + success: afterLoadBands, + error: app.ajaxError + }); + } + + function search() { + did_show_band_page = true; + var queryString = 'srch_b=1&page='+page_num+'&'; + + // order by + var orderby = $('#band_order_by').val(); + if (typeof orderby != 'undefined' && orderby.length > 0) { + queryString += "orderby=" + orderby + '&'; + } + // genre filter + var genre = $('#band_genre').val(); + if (typeof genre != 'undefined' && !(genre === '')) { + queryString += "genre=" + genre + '&'; + } + // distance filter + var query_param = $('#band_query_distance').val(); + if (query_param !== null && query_param.length > 0) { + var matches = query_param.match(/(\d+)/); + if (0 < matches.length) { + var distance = matches[0]; + queryString += "distance=" + distance + '&'; + } + } + loadBands(queryString); + } + + function refreshDisplay() { + clearResults(); + search(); + } + + function afterLoadBands(mList) { + // display the 'no bands' banner if appropriate + var $noBandsFound = $('#bands-none-found'); + bandList = mList; + + if(bandList.length == 0) { + $noBandsFound.show(); + bands = []; + } else { + $noBandsFound.hide(); + bands = bandList['bands']; + if (!(typeof bands === 'undefined')) { + $('#band-filter-city').text(bandList['city']); + if (0 == page_count) { + page_count = bandList['page_count']; + } + renderBands(); + } + } + } + + /** + * Render a list of bands + */ + function renderBands() { + var ii, len; + var mTemplate = $('#template-find-band-row').html(); + var pTemplate = $('#template-band-player-info').html(); + var aTemplate = $('#template-band-action-btns').html(); + var bVals, bb, renderings=''; + var instr_logos, instr; + var players, playerVals, aPlayer; + + for (ii=0, len=bands.length; ii < len; ii++) { + bb = bands[ii]; + instr_logos = ''; + /*for (var jj=0, ilen=bb['instruments'].length; jj '; + }*/ + players = ''; + playerVals = {}; + for (var jj=0, ilen=bb['players'].length; jj '; + }*/ + + playerVals = { + player_name: aPlayer.name, + profile_url: '/#/profile/' + aPlayer.user_id, + avatar_url: context.JK.resolveAvatarUrl(aPlayer.photo_url), + player_instruments: player_instrs + }; + players += context.JK.fillTemplate(pTemplate, playerVals); + } + var actionVals = { + profile_url: "/#/profile/" + bb.id, + button_follow: bb['is_following'] ? '' : 'button-orange', + button_message: 'button-orange' + }; + var band_actions = context.JK.fillTemplate(aTemplate, actionVals); + + bVals = { + avatar_url: context.JK.resolveAvatarUrl(bb.photo_url), + profile_url: "/#/profile/" + bb.id, + band_name: bb.name, + band_location: bb.city + ', ' + bb.state, + instruments: instr_logos, + biography: bb['biography'], + follow_count: bb['follow_count'], + recording_count: bb['recording_count'], + session_count: bb['session_count'], + band_id: bb['id'], + band_follow_template: players, + band_action_template: band_actions + }; + var band_row = context.JK.fillTemplate(mTemplate, bVals); + renderings += band_row; + } + $('#band-filter-results').append(renderings); + + $('.search-m-follow').on('click', followBand); + } + + function beforeShow(data) { + } + + function afterShow(data) { + if (!did_show_band_page) { + refreshDisplay(); + } + } + + function clearResults() { + bands = {}; + $('#band-filter-results').empty(); + page_num = 1; + page_count = 0; + } + + function followBand(evt) { + // if the band is already followed, remove the button-orange class, and prevent + // the link from working + if (0 == $(this).closest('.button-orange').size()) return false; + $(this).click(function(ee) {ee.preventDefault();}); + + evt.stopPropagation(); + var newFollowing = {}; + newFollowing.user_id = $(this).parent().data('band-id'); + var url = "/api/users/" + context.JK.currentUserId + "/followings"; + $.ajax({ + type: "POST", + dataType: "json", + contentType: 'application/json', + url: url, + data: JSON.stringify(newFollowing), + processData: false, + success: function(response) { + // remove the orange look to indicate it's not selectable + $('div[data-band-id='+newFollowing.user_id+'] .search-m-follow').removeClass('button-orange'); + }, + error: app.ajaxError + }); + } + + function events() { + $('#band_query_distance').change(refreshDisplay); + $('#band_genre').change(refreshDisplay); + $('#band_order_by').change(refreshDisplay); + + $('#band-filter-results').bind('scroll', function() { + if ($(this).scrollTop() + $(this).innerHeight() >= $(this)[0].scrollHeight) { + if (page_num < page_count) { + page_num += 1; + search(); + } + } + }); + } + + /** + * Initialize, + */ + function initialize() { + var screenBindings = { + 'beforeShow': beforeShow, + 'afterShow': afterShow + }; + app.bindScreen('bands', screenBindings); + + events(); + } + + this.initialize = initialize; + this.renderBands = renderBands; + this.afterShow = afterShow; + + this.clearResults = clearResults; + + return this; + }; + +})(window,jQuery); \ No newline at end of file diff --git a/web/app/views/api_search/index.rabl b/web/app/views/api_search/index.rabl index 4c66715b5..581566cd8 100644 --- a/web/app/views/api_search/index.rabl +++ b/web/app/views/api_search/index.rabl @@ -58,6 +58,36 @@ if @search.musicians_filter.present? } end +if @search.bands_filter.present? + + node :page_count do |foo| + @search.page_count + end + + child(:bands_filter => :bands) { + attributes :id, :name, :city, :state, :country, :email, :photo_url, :biography, :logo_url + + node :is_following do |band| + @search.is_follower?(band) + end + + child :genres => :genre do + attributes :genre_id, :description + end + + child :users => :players do |pl| + node :user_id do |uu| uu.id end + node :photo_url do |uu| uu.photo_url end + node :name do |uu| uu.name end + node :instruments do |uu| uu.instruments.map(&:id).join(',') end + end + + node :follow_count do |band| @search.follow_count(band) end + node :recording_count do |band| @search.record_count(band) end + node :session_count do |band| @search.session_count(band) end + } +end + unless @search.fans.nil? || @search.fans.size == 0 child(:fans => :fans) { attributes :id, :first_name, :last_name, :name, :location, :photo_url diff --git a/web/app/views/clients/_bands.html.erb b/web/app/views/clients/_bands.html.erb index 4da67b440..091244ff5 100644 --- a/web/app/views/clients/_bands.html.erb +++ b/web/app/views/clients/_bands.html.erb @@ -28,7 +28,7 @@

{instruments}


- {friend_count}    {follow_count}    {recording_count}    {session_count}

+ {follow_count}    {recording_count}    {session_count}


@@ -38,27 +38,24 @@ {band_action_template}
-
+

FOLLOWING: - {band_follow_template}
+ {band_follow_template}

- diff --git a/web/app/views/clients/index.html.erb b/web/app/views/clients/index.html.erb index 6985978e4..e7d215f56 100644 --- a/web/app/views/clients/index.html.erb +++ b/web/app/views/clients/index.html.erb @@ -151,6 +151,9 @@ var findMusicianScreen = new JK.FindMusicianScreen(JK.app); findMusicianScreen.initialize(); + var findBandScreen = new JK.FindBandScreen(JK.app); + findBandScreen.initialize(); + var sessionScreen = new JK.SessionScreen(JK.app); sessionScreen.initialize(); var sessionSettingsDialog = new JK.SessionSettingsDialog(JK.app, sessionScreen); From 742402dfa23f1d3b59a64bafdd8085a17b0a87a6 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 16 Dec 2013 12:47:59 -0600 Subject: [PATCH 27/40] vrfs-884: merge conflict fixes --- ruby/lib/jam_ruby/models/band.rb | 77 ++++++++++++++++---------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band.rb b/ruby/lib/jam_ruby/models/band.rb index 0053de3de..131883ade 100644 --- a/ruby/lib/jam_ruby/models/band.rb +++ b/ruby/lib/jam_ruby/models/band.rb @@ -2,8 +2,8 @@ module JamRuby class Band < ActiveRecord::Base attr_accessible :name, :website, :biography, :city, :state, - :country, :original_fpfile_photo, :cropped_fpfile_photo, - :cropped_s3_path_photo, :crop_selection_photo, :photo_url + :country, :original_fpfile_photo, :cropped_fpfile_photo, + :cropped_s3_path_photo, :crop_selection_photo, :photo_url attr_accessor :updating_photo @@ -101,11 +101,11 @@ module JamRuby if hide_private recordings = Recording.joins(:band_recordings) - .where(:bands_recordings => {:band_id => "#{band_id}"}, :public => true) + .where(:bands_recordings => {:band_id => "#{band_id}"}, :public => true) else recordings = Recording.joins(:band_recordings) - .where(:bands_recordings => {:band_id => "#{band_id}"}) + .where(:bands_recordings => {:band_id => "#{band_id}"}) end return recordings @@ -144,7 +144,7 @@ module JamRuby validate_genres(genres, false) band = Band.new() - # band update + # band update else validate_genres(genres, true) band = Band.find(id) @@ -212,12 +212,12 @@ module JamRuby 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) - ) + :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) @@ -230,13 +230,14 @@ module JamRuby 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 - ) + :original_fpfile_photo => nil, + :cropped_fpfile_photo => nil, + :cropped_s3_path_photo => nil, + :crop_selection_photo => nil, + :photo_url => nil + ) end + end def check_lat_lng if (city_changed? || state_changed? || country_changed?) @@ -261,32 +262,32 @@ module JamRuby end private - def self.validate_genres(genres, is_nil_ok) - if is_nil_ok && genres.nil? - return - end + def self.validate_genres(genres, is_nil_ok) + if is_nil_ok && genres.nil? + return + end - if genres.nil? + 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 - else - if genres.size < Limits::MIN_GENRES_PER_BAND - raise JamRuby::JamArgumentError, ValidationMessages::GENRE_MINIMUM_NOT_MET - end + end - if genres.size > Limits::MAX_GENRES_PER_BAND - raise JamRuby::JamArgumentError, ValidationMessages::GENRE_LIMIT_EXCEEDED - end + if genres.size > Limits::MAX_GENRES_PER_BAND + raise JamRuby::JamArgumentError, ValidationMessages::GENRE_LIMIT_EXCEEDED 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 + 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 From aec6e52acec5bac04b029104512fef70b7c1f4a0 Mon Sep 17 00:00:00 2001 From: Anthony Davis Date: Mon, 16 Dec 2013 14:42:34 -0600 Subject: [PATCH 28/40] VRFS-907 - removed links to jeffkoke.com also fixing character --- web/app/views/corps/news.html.erb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/app/views/corps/news.html.erb b/web/app/views/corps/news.html.erb index 5160df07c..4c7d4cdf4 100644 --- a/web/app/views/corps/news.html.erb +++ b/web/app/views/corps/news.html.erb @@ -2,15 +2,15 @@ <% provide(:purpose, 'news') %>

News

-

August 27, 2013 -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.  READ MORE �

+

August 27, 2013 -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.  READ MORE »

-

August 15, 2013 -- Aliquam et nisl vel ligula consectetuer suscipit. Morbi euismod enim eget neque. Donec sagittis massa. Vestibulum quis augue sit amet ipsum laoreet pretium. Nulla facilisi.  READ MORE �

+

August 15, 2013 -- Aliquam et nisl vel ligula consectetuer suscipit. Morbi euismod enim eget neque. Donec sagittis massa. Vestibulum quis augue sit amet ipsum laoreet pretium. Nulla facilisi.  READ MORE »

-

August 2, 2013 -- Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante.   READ MORE �

+

August 2, 2013 -- Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante.   READ MORE »

-

July 12, 2013 -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.  READ MORE �

+

July 12, 2013 -- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.  READ MORE »

-

July 7, 2013 -- Aliquam et nisl vel ligula consectetuer suscipit. Morbi euismod enim eget neque. Donec sagittis massa. Vestibulum quis augue sit amet ipsum laoreet pretium. Nulla facilisi.  READ MORE �

+

July 7, 2013 -- Aliquam et nisl vel ligula consectetuer suscipit. Morbi euismod enim eget neque. Donec sagittis massa. Vestibulum quis augue sit amet ipsum laoreet pretium. Nulla facilisi.  READ MORE »

From 60b59a88c7836bf59232dcd37c5df390c14a6f7f Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Mon, 16 Dec 2013 20:32:17 -0600 Subject: [PATCH 29/40] vrfs-884: fixing tests for commit --- ruby/lib/jam_ruby/models/band.rb | 39 ++++++++----------- ruby/lib/jam_ruby/models/search.rb | 3 +- ruby/spec/jam_ruby/models/band_search_spec.rb | 2 + web/spec/features/musician_search_spec.rb | 6 +-- web/spec/requests/musician_search_api_spec.rb | 2 +- 5 files changed, 22 insertions(+), 30 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band.rb b/ruby/lib/jam_ruby/models/band.rb index 131883ade..e29c8295e 100644 --- a/ruby/lib/jam_ruby/models/band.rb +++ b/ruby/lib/jam_ruby/models/band.rb @@ -130,11 +130,10 @@ module JamRuby # 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) # new band - if id.nil? + if id.blank? # ensure person creating this Band is a Musician unless user.musician? @@ -173,35 +172,28 @@ module JamRuby # country band.country = country unless country.nil? - # genres - unless genres.nil? - ActiveRecord::Base.transaction do - # delete all genres for this band first - unless band.id.nil? || band.id.length == 0 - band.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) - band.genres << g - end - end - end - # 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.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 - if id.nil? - BandMusician.create(:band_id => band.id, :user_id => user_id, :admin => true) - end + BandMusician.create(:band_id => band.id, :user_id => user_id, :admin => true) if id.blank? return band end @@ -243,6 +235,7 @@ module JamRuby if (city_changed? || state_changed? || country_changed?) update_lat_lng end + true end def update_lat_lng diff --git a/ruby/lib/jam_ruby/models/search.rb b/ruby/lib/jam_ruby/models/search.rb index e3f200677..930bb109c 100644 --- a/ruby/lib/jam_ruby/models/search.rb +++ b/ruby/lib/jam_ruby/models/search.rb @@ -41,8 +41,7 @@ module JamRuby search_results.take(LIMIT).each do |result| if result.class == User if result.musician - @musicians_filter.push(result) - @search_type = PARAM_MUSICIAN + @musicians.push(result) else @fans.push(result) end diff --git a/ruby/spec/jam_ruby/models/band_search_spec.rb b/ruby/spec/jam_ruby/models/band_search_spec.rb index ce9ca8767..40e26d50f 100644 --- a/ruby/spec/jam_ruby/models/band_search_spec.rb +++ b/ruby/spec/jam_ruby/models/band_search_spec.rb @@ -5,6 +5,8 @@ describe User do let(:user) { FactoryGirl.create(:user) } 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) diff --git a/web/spec/features/musician_search_spec.rb b/web/spec/features/musician_search_spec.rb index b2ce07802..e7c29d7aa 100644 --- a/web/spec/features/musician_search_spec.rb +++ b/web/spec/features/musician_search_spec.rb @@ -24,14 +24,12 @@ describe "Musician Search", :js => true, :type => :feature, :capybara_feature => end it "shows submits query" do - find("a#btn-refresh-musicians").trigger(:click) expect(page).to have_selector('#musician-filter-results .musician-list-result') end it "shows blank result set" do - expect(page).to have_selector('#instrument') - find('#instrument').find(:xpath, 'option[2]').select_option - find("a#btn-refresh-musicians").trigger(:click) + expect(page).to have_selector('#musician_instrument') + find('#musician_instrument').find(:xpath, 'option[2]').select_option expect(page).to_not have_selector('#musician-filter-results .musician-list-result') end diff --git a/web/spec/requests/musician_search_api_spec.rb b/web/spec/requests/musician_search_api_spec.rb index 11680a2a5..a48a1c6b1 100644 --- a/web/spec/requests/musician_search_api_spec.rb +++ b/web/spec/requests/musician_search_api_spec.rb @@ -29,7 +29,7 @@ describe "Musician Search API", :type => :api do it "default search" do get_query good_response - expect(json['musicians'].count).to be [Search::M_PER_PAGE, User.musicians_geocoded.count].min + expect(json['musicians'].count).to be [Search::M_PER_PAGE, User.musicians.count].min end context 'location filtering' do From 932de5cc35dc8ac2b2a733309d556778cbc82670 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Mon, 16 Dec 2013 23:22:30 -0500 Subject: [PATCH 30/40] VRFS-877 band photo bug fixes --- web/app/assets/javascripts/band_setup.js | 4 ++-- web/app/controllers/api_bands_controller.rb | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/web/app/assets/javascripts/band_setup.js b/web/app/assets/javascripts/band_setup.js index 5752a35e4..996190051 100644 --- a/web/app/assets/javascripts/band_setup.js +++ b/web/app/assets/javascripts/band_setup.js @@ -229,8 +229,8 @@ userNames = []; userIds = []; userPhotoUrls = []; - //bandId = "1158c8b6-4c92-47dc-82bf-1e390c4f9b2c"; - bandId = $("#hdn-band-id").val(); + bandId = "1158c8b6-4c92-47dc-82bf-1e390c4f9b2c"; + //bandId = $("#hdn-band-id").val(); resetForm(); } diff --git a/web/app/controllers/api_bands_controller.rb b/web/app/controllers/api_bands_controller.rb index 483237bae..1d441e21c 100644 --- a/web/app/controllers/api_bands_controller.rb +++ b/web/app/controllers/api_bands_controller.rb @@ -197,9 +197,9 @@ class ApiBandsController < ApiController @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 + render :json => { :message => "Unexpected error updating photo."}, :status => :unprocessable_entity else - respond_with @band, responder: ApiResponder, status: 200 + render :json => {}, :status => :ok end end @@ -207,9 +207,9 @@ class ApiBandsController < ApiController @band.delete_photo(Rails.application.config.aws_bucket_public) if @band.errors.any? - respond_with @band, status: :unprocessable_entity + render :json => { :message => "Unexpected error deleting photo."}, :status => :unprocessable_entity else - respond_with @band, responder: ApiResponder, status: 204 + render :json => {}, :status => :ok end end From a1983d9803148fea1c2fd2cce5f832ebc7af3819 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Mon, 16 Dec 2013 23:23:59 -0500 Subject: [PATCH 31/40] VRFS-877 band photo bug fixes --- ruby/lib/jam_ruby/models/band.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ruby/lib/jam_ruby/models/band.rb b/ruby/lib/jam_ruby/models/band.rb index e29c8295e..3ce6fee36 100644 --- a/ruby/lib/jam_ruby/models/band.rb +++ b/ruby/lib/jam_ruby/models/band.rb @@ -216,9 +216,9 @@ module JamRuby 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) + unless self.cropped_s3_path_photo.nil? + S3Util.delete(aws_bucket, File.dirname(self.cropped_s3_path_photo) + '/cropped.jpg') + S3Util.delete(aws_bucket, self.cropped_s3_path_photo) end return self.update_attributes( From 4329338fa86c43246ba72880f7b739b5997c9e2a Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Tue, 17 Dec 2013 10:58:35 -0600 Subject: [PATCH 32/40] vrfs-884: added check for client_id==undefined in participant_delete method --- web/app/controllers/api_music_sessions_controller.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/web/app/controllers/api_music_sessions_controller.rb b/web/app/controllers/api_music_sessions_controller.rb index 1d1028a8b..9809d49d0 100644 --- a/web/app/controllers/api_music_sessions_controller.rb +++ b/web/app/controllers/api_music_sessions_controller.rb @@ -101,11 +101,11 @@ class ApiMusicSessionsController < ApiController def participant_delete client_id = params[:id] - @connection = Connection.find_by_client_id!(client_id) - music_session = MusicSession.find(@connection.music_session_id) - - MusicSessionManager.new.participant_delete(current_user, @connection, music_session) - + if client_id.present? && client_id != 'undefined' + @connection = Connection.find_by_client_id!(client_id) + music_session = MusicSession.find(@connection.music_session_id) + MusicSessionManager.new.participant_delete(current_user, @connection, music_session) + end respond_with @connection, responder: ApiResponder end From 020f9d544eb3b863b5bcda6f5532a3aec797a861 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Tue, 17 Dec 2013 10:59:16 -0600 Subject: [PATCH 33/40] vrfs-884: tweaking layout --- web/app/assets/javascripts/findBand.js | 29 ++++---- .../assets/stylesheets/client/band.css.scss | 19 +++++ .../stylesheets/client/web_filter.css.scss | 70 +++++++++++++++++++ web/app/views/api_search/index.rabl | 2 +- web/app/views/clients/_bands.html.erb | 20 +++--- web/lib/tasks/sample_data.rake | 13 ++++ 6 files changed, 126 insertions(+), 27 deletions(-) create mode 100644 web/app/assets/stylesheets/client/web_filter.css.scss diff --git a/web/app/assets/javascripts/findBand.js b/web/app/assets/javascripts/findBand.js index a8a9714db..2475521d6 100644 --- a/web/app/assets/javascripts/findBand.js +++ b/web/app/assets/javascripts/findBand.js @@ -91,24 +91,19 @@ for (ii=0, len=bands.length; ii < len; ii++) { bb = bands[ii]; instr_logos = ''; - /*for (var jj=0, ilen=bb['instruments'].length; jj '; - }*/ players = ''; playerVals = {}; for (var jj=0, ilen=bb['players'].length; jj '; - }*/ + } playerVals = { player_name: aPlayer.name, @@ -124,19 +119,25 @@ button_message: 'button-orange' }; var band_actions = context.JK.fillTemplate(aTemplate, actionVals); + var bgenres = ''; + for (jj=0, ilen=bb['genres'].length; jj'; + } + bgenres += '
'; bVals = { avatar_url: context.JK.resolveAvatarUrl(bb.photo_url), profile_url: "/#/profile/" + bb.id, band_name: bb.name, band_location: bb.city + ', ' + bb.state, + genres: bgenres, instruments: instr_logos, biography: bb['biography'], follow_count: bb['follow_count'], recording_count: bb['recording_count'], session_count: bb['session_count'], band_id: bb['id'], - band_follow_template: players, + band_player_template: players, band_action_template: band_actions }; var band_row = context.JK.fillTemplate(mTemplate, bVals); @@ -171,7 +172,7 @@ evt.stopPropagation(); var newFollowing = {}; - newFollowing.user_id = $(this).parent().data('band-id'); + newFollowing.band_id = $(this).parent().data('band-id'); var url = "/api/users/" + context.JK.currentUserId + "/followings"; $.ajax({ type: "POST", @@ -182,7 +183,7 @@ processData: false, success: function(response) { // remove the orange look to indicate it's not selectable - $('div[data-band-id='+newFollowing.user_id+'] .search-m-follow').removeClass('button-orange'); + $('div[data-band-id='+newFollowing.band_id+'] .search-m-follow').removeClass('button-orange'); }, error: app.ajaxError }); diff --git a/web/app/assets/stylesheets/client/band.css.scss b/web/app/assets/stylesheets/client/band.css.scss index 18f505eb1..63152401a 100644 --- a/web/app/assets/stylesheets/client/band.css.scss +++ b/web/app/assets/stylesheets/client/band.css.scss @@ -270,3 +270,22 @@ .band-profile-block-city { font-size:12px; } + +#band-filter-results { + margin: 0 10px 5px 10px; + overflow: auto; + height: 100%; + width: 100%; +} + +.band-list-result { + padding-top: 5px; + padding-right: 5px; + padding-left: 5px; +} + +.band-wrapper { + overflow: auto; + height: 480px; + width: 100%; +} diff --git a/web/app/assets/stylesheets/client/web_filter.css.scss b/web/app/assets/stylesheets/client/web_filter.css.scss new file mode 100644 index 000000000..b84bc97ce --- /dev/null +++ b/web/app/assets/stylesheets/client/web_filter.css.scss @@ -0,0 +1,70 @@ +@import "client/common.css.scss"; +@charset "UTF-8"; + +.filter-results { + + li { + position: relative; + border-bottom:solid 1px shade($ColorElementPrimary, 20); + clear:both; + } + + li strong { + font-weight:bold; + } + + li.offline { + background-color: shade($ColorElementPrimary, 20); + color: shade($text, 10); + opacity:0.5; + ms-filter: "alpha(opacity=50)"; + } + + .avatar-small { + float:left; + padding:1px; + width:36px; + height:36px; + background-color:#ed3618; + margin:10px; + -webkit-border-radius:18px; + -moz-border-radius:18px; + border-radius:18px; + } + + .avatar-small img { + width: 36px; + height: 36px; + -webkit-border-radius:18px; + -moz-border-radius:18px; + border-radius:18px; + } + + li a { + color:#B3DD15; + } + + li a:hover { + color:#FFF; + } + + .result-name { + float:left; + font-size:12px; + margin-top:12px; + font-weight:bold; + } + + .result-location { + font-size:11px; + color:#D5E2E4; + font-weight:200; + } + + .results-wrapper { + width: 300px; + overflow-y:auto; + overflow-x:hidden; + } +} + diff --git a/web/app/views/api_search/index.rabl b/web/app/views/api_search/index.rabl index 581566cd8..e7102cee9 100644 --- a/web/app/views/api_search/index.rabl +++ b/web/app/views/api_search/index.rabl @@ -71,7 +71,7 @@ if @search.bands_filter.present? @search.is_follower?(band) end - child :genres => :genre do + child :genres => :genres do attributes :genre_id, :description end diff --git a/web/app/views/clients/_bands.html.erb b/web/app/views/clients/_bands.html.erb index 091244ff5..473ecf9bf 100644 --- a/web/app/views/clients/_bands.html.erb +++ b/web/app/views/clients/_bands.html.erb @@ -9,7 +9,7 @@ <%= form_tag('', :id => 'find-band-form') do -%> <%= content_tag(:div, render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_BAND}), :class => 'band-filter', :id => 'session-controls') %> <%= content_tag(:div, :class => 'content-scroller') do -%> - <%= content_tag(:div, content_tag(:div, '', :id => 'band-filter-results'), :class => 'content-wrapper band-wrapper') %> + <%= content_tag(:div, content_tag(:div, '', :id => 'band-filter-results', :class => 'filter-results'), :class => 'content-wrapper band-wrapper') %> <% end -%> <% end -%> <% end -%> @@ -24,24 +24,20 @@
{band_name}
- {band_location} + {band_location}

-
{instruments}
-

- {follow_count}    {recording_count}    {session_count}


+
{genres}
+

+ {follow_count}    {recording_count}    {session_count}

-

+

{biography}

-
- {band_action_template} -
+
{band_action_template}
-
- FOLLOWING: - {band_follow_template}
+ {band_player_template}

diff --git a/web/lib/tasks/sample_data.rake b/web/lib/tasks/sample_data.rake index dee36061d..f2c63850c 100644 --- a/web/lib/tasks/sample_data.rake +++ b/web/lib/tasks/sample_data.rake @@ -22,6 +22,10 @@ namespace :db do make_band_members end + task populate_band_genres: :environment do + make_band_genres + end + desc "Fill database with music session sample data" task populate_music_sessions: :environment do make_users(10) if 14 > User.count @@ -72,6 +76,15 @@ def make_band_members end end +def make_band_genres + Band.find_each do |bb| + next if bb.genres.present? + Genre.order('RANDOM()').limit(rand(3)+1).each do |gg| + bb.genres << gg + end + end +end + def make_bands 10.times do |nn| name = Faker::Name.name From daf9b38a9e3c9c69b52d39d0778b4a1ad919c819 Mon Sep 17 00:00:00 2001 From: Anthony Davis Date: Tue, 17 Dec 2013 22:07:24 -0600 Subject: [PATCH 34/40] VRFS-909 - pushing typo fix in legal email --- web/app/views/corps/terms.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/views/corps/terms.html.erb b/web/app/views/corps/terms.html.erb index 17c00b04e..2a345a72c 100644 --- a/web/app/views/corps/terms.html.erb +++ b/web/app/views/corps/terms.html.erb @@ -459,7 +459,7 @@ discover Content that infringes any or violates any of your other rights, which you believe is defamatory, pornographic, obscene, racist or otherwise liable to cause widespread offence, or which constitutes impersonation, harassment, spam or otherwise violates these Terms of Service or applicable law, please - report this to us at legal@jamkazam.com. + report this to us at legal@jamkazam.com.

From d5b53c34062eb07dc3cf6c3aaa828e2856f2d41f Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Wed, 18 Dec 2013 22:33:56 -0500 Subject: [PATCH 35/40] remove hard-coded band ID --- web/app/assets/javascripts/band_setup.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/app/assets/javascripts/band_setup.js b/web/app/assets/javascripts/band_setup.js index 996190051..5752a35e4 100644 --- a/web/app/assets/javascripts/band_setup.js +++ b/web/app/assets/javascripts/band_setup.js @@ -229,8 +229,8 @@ userNames = []; userIds = []; userPhotoUrls = []; - bandId = "1158c8b6-4c92-47dc-82bf-1e390c4f9b2c"; - //bandId = $("#hdn-band-id").val(); + //bandId = "1158c8b6-4c92-47dc-82bf-1e390c4f9b2c"; + bandId = $("#hdn-band-id").val(); resetForm(); } From 4e136659e8f9b8681b3d1cf8f1923593a58f5501 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 18 Dec 2013 17:48:55 -0600 Subject: [PATCH 36/40] vrfs-916: added following? method --- ruby/lib/jam_ruby/models/user.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index b9d81bdb2..7279fa068 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -261,6 +261,10 @@ module JamRuby return self.band_likes.size end + def following?(user) + self.followings.exists?(user) + end + def follower_count return self.followers.size end From f7c08ce472ea22be9cdd6917b4e296ca963a038c Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 18 Dec 2013 17:59:02 -0600 Subject: [PATCH 37/40] vrfs-916: added fan page branching logic --- web/app/assets/javascripts/profile.js | 185 +++++++++++++----------- web/app/views/api_users/show.rabl | 16 +- web/app/views/clients/_profile.html.erb | 7 +- 3 files changed, 120 insertions(+), 88 deletions(-) diff --git a/web/app/assets/javascripts/profile.js b/web/app/assets/javascripts/profile.js index 273d88fa9..a5db58050 100644 --- a/web/app/assets/javascripts/profile.js +++ b/web/app/assets/javascripts/profile.js @@ -6,7 +6,7 @@ context.JK.ProfileScreen = function(app) { var logger = context.JK.logger; var userId; - var user = {}; + var user = null; var instrument_logo_map = context.JK.getInstrumentIconMap24(); @@ -24,6 +24,7 @@ function beforeShow(data) { userId = data.id; + user = null; } function afterShow(data) { @@ -45,6 +46,69 @@ $('.profile-nav a.#profile-about-link').addClass('active'); } + function getUser() { + if (user === null) { + var url = "/api/users/" + userId; + $.ajax({ + type: "GET", + dataType: "json", + url: url, + async: false, + processData:false, + success: function(response) { + user = response; + }, + error: function(jqXHR, textStatus, errorMessage) { + user = null; + app.ajaxError(jqXHR, textStatus, errorMessage); + } + }); + } + return user; + } + + function isMusician() { + if (getUser()) { + return user.musician === true; + } + return false; + } + + function configUserType() { + if (isMusician()) { + $('#profile-history-link').show(); + $('#profile-bands-link').show(); + $('#profile-instruments').show(); + $('#profile-session-stats').show(); + $('#profile-recording-stats').show(); + + $('#profile-following-stats').hide(); + $('#profile-favorites-stats').hide(); + + $('#btn-add-friend').show(); + $('#profile-social-left').show(); + + $('#profile-type-label').text('musician'); + $('#profile-location-label').text('Location'); + + } else { + $('#profile-history-link').hide(); + $('#profile-bands-link').hide(); + $('#profile-instruments').hide(); + $('#profile-session-stats').hide(); + $('#profile-recording-stats').hide(); + + $('#profile-following-stats').show(); + $('#profile-favorites-stats').show(); + + $('#btn-add-friend').hide(); + $('#profile-social-left').hide(); + + $('#profile-type-label').text('fan'); + $('#profile-location-label').text('Presence'); + } + } + /****************** MAIN PORTION OF SCREEN *****************/ // events for main screen function events() { @@ -94,27 +158,7 @@ } function isFriend() { - var alreadyFriend = false; - - var url = "/api/users/" + context.JK.currentUserId + "/friends/" + userId; - $.ajax({ - type: "GET", - dataType: "json", - url: url, - async: false, - processData: false, - success: function(response) { - if (response.id !== undefined) { - alreadyFriend = true; - } - else { - alreadyFriend = false; - } - }, - error: app.ajaxError - }); - - return alreadyFriend; + return getUser() ? user.is_friend : false; } function friendRequestCallback() { @@ -186,27 +230,7 @@ } function isFollowing() { - var alreadyFollowing = false; - - var url = "/api/users/" + context.JK.currentUserId + "/followings/" + userId; - $.ajax({ - type: "GET", - dataType: "json", - url: url, - async: false, - processData: false, - success: function(response) { - if (response.id !== undefined) { - alreadyFollowing = true; - } - else { - alreadyFollowing = false; - } - }, - error: app.ajaxError - }); - - return alreadyFollowing; + return getUser() ? user.is_following : false; } function configureFollowingButton(following) { @@ -261,21 +285,9 @@ function bindAbout() { $('#profile-instruments').empty(); - var url = "/api/users/" + userId; - $.ajax({ - type: "GET", - dataType: "json", - url: url, - async: false, - processData:false, - success: function(response) { - user = response; - }, - error: app.ajaxError - }); - - if (user) { + if (getUser()) { + configUserType(); // name $('#profile-username').html(user.name); @@ -313,11 +325,16 @@ text = user.follower_count > 1 || user.follower_count === 0 ? " Followers" : " Follower"; $('#profile-follower-stats').html(user.follower_count + text); - text = user.session_count > 1 || user.session_count === 0 ? " Sessions" : " Session"; - $('#profile-session-stats').html(user.session_count + text); + if (user.musician === true) { + text = user.session_count > 1 || user.session_count === 0 ? " Sessions" : " Session"; + $('#profile-session-stats').html(user.session_count + text); - text = user.recording_count > 1 || user.recording_count === 0 ? " Recordings" : " Recording"; - $('#profile-recording-stats').html(user.recording_count + text); + text = user.recording_count > 1 || user.recording_count === 0 ? " Recordings" : " Recording"; + $('#profile-recording-stats').html(user.recording_count + text); + } else { + text = " Following"; + $('#profile-following-stats').html(user.following_count + text); + } $('#profile-biography').html(user.biography); } @@ -345,29 +362,31 @@ } function bindSocial() { - // FRIENDS - var url = "/api/users/" + userId + "/friends"; - $.ajax({ - type: "GET", - dataType: "json", - url: url, - async: false, - processData:false, - success: function(response) { - $.each(response, function(index, val) { - var template = $('#template-profile-social').html(); - var friendHtml = context.JK.fillTemplate(template, { - avatar_url: context.JK.resolveAvatarUrl(val.photo_url), - userName: val.name, - location: val.location, - type: "Friends" - }); + if (isMusician()) { + // FRIENDS + var url = "/api/users/" + userId + "/friends"; + $.ajax({ + type: "GET", + dataType: "json", + url: url, + async: false, + processData:false, + success: function(response) { + $.each(response, function(index, val) { + var template = $('#template-profile-social').html(); + var friendHtml = context.JK.fillTemplate(template, { + avatar_url: context.JK.resolveAvatarUrl(val.photo_url), + userName: val.name, + location: val.location, + type: "Friends" + }); - $('#profile-social-friends').append(friendHtml); - }); - }, - error: app.ajaxError - }); + $('#profile-social-friends').append(friendHtml); + }); + }, + error: app.ajaxError + }); + } // FOLLOWINGS (USERS) url = "/api/users/" + userId + "/followings"; diff --git a/web/app/views/api_users/show.rabl b/web/app/views/api_users/show.rabl index 9a35978ef..4c63e2c39 100644 --- a/web/app/views/api_users/show.rabl +++ b/web/app/views/api_users/show.rabl @@ -1,11 +1,23 @@ object @user -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, :band_like_count, :follower_count, :following_count, :band_following_count, :recording_count, :session_count, -:biography +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, :band_like_count, :follower_count, :following_count, :band_following_count, :recording_count, :session_count, :biography + +if @user.musician? + node :location do @user.location end +else + node :location do @user.online ? 'Online' : 'Offline' end +end # give back more info if the user being fetched is yourself if @user == current_user attributes :email, :original_fpfile, :cropped_fpfile, :crop_selection, :session_settings, :show_whats_next, :subscribe_email +elsif current_user + node :is_friend do |uu| + @user.friends?(current_user) + end + node :is_following do |uu| + @user.following?(current_user) + end end unless @user.friends.nil? || @user.friends.size == 0 diff --git a/web/app/views/clients/_profile.html.erb b/web/app/views/clients/_profile.html.erb index 002a4add9..84b4ae9fe 100644 --- a/web/app/views/clients/_profile.html.erb +++ b/web/app/views/clients/_profile.html.erb @@ -5,7 +5,7 @@ <%= image_tag "content/icon_profile.png", :size => "19x19" %> -

musician profile

+

musician profile

<%= render "screen_navigation" %> @@ -47,11 +47,12 @@
-

Location:


+

Location:





Stats:




+


@@ -149,4 +150,4 @@
{userName}
{location}
- \ No newline at end of file + From 4b3b8491b3273f48e544226638e4e16231c773ab Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 18 Dec 2013 22:10:55 -0600 Subject: [PATCH 38/40] vrfs-916: added favorite_count method --- ruby/lib/jam_ruby/models/user.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index 7279fa068..cc933e38f 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -622,6 +622,10 @@ module JamRuby favorite.save end + def favorite_count + 0 # FIXME: update this with recording likes count when implemented + end + def self.delete_favorite(user_id, recording_id) JamRuby::UserFavorite.delete_all "(user_id = '#{user_id}' AND recording_id = '#{recording_id}')" end From 0ecbf9f0477e5a539b6c228d5eb259a4a06ea049 Mon Sep 17 00:00:00 2001 From: Jonathan Kolyer Date: Wed, 18 Dec 2013 22:12:28 -0600 Subject: [PATCH 39/40] vrfs-916: added toggles for fan/musician; misc fan tweaks --- web/app/assets/javascripts/profile.js | 53 ++++++++++++++------- web/app/controllers/api_users_controller.rb | 5 +- web/app/views/api_users/show.rabl | 2 +- web/app/views/clients/_account.html.erb | 4 ++ web/app/views/clients/_profile.html.erb | 2 + web/app/views/users/_user_dropdown.html.erb | 8 ++-- 6 files changed, 53 insertions(+), 21 deletions(-) diff --git a/web/app/assets/javascripts/profile.js b/web/app/assets/javascripts/profile.js index a5db58050..fb9bab119 100644 --- a/web/app/assets/javascripts/profile.js +++ b/web/app/assets/javascripts/profile.js @@ -74,7 +74,11 @@ return false; } - function configUserType() { + function isCurrentUser() { + return userId === context.JK.currentUserId; + } + + function configureUserType() { if (isMusician()) { $('#profile-history-link').show(); $('#profile-bands-link').show(); @@ -82,11 +86,11 @@ $('#profile-session-stats').show(); $('#profile-recording-stats').show(); - $('#profile-following-stats').hide(); - $('#profile-favorites-stats').hide(); + // $('#profile-following-stats').hide(); + // $('#profile-favorites-stats').hide(); $('#btn-add-friend').show(); - $('#profile-social-left').show(); + $('.profile-social-left').show(); $('#profile-type-label').text('musician'); $('#profile-location-label').text('Location'); @@ -98,20 +102,28 @@ $('#profile-session-stats').hide(); $('#profile-recording-stats').hide(); - $('#profile-following-stats').show(); - $('#profile-favorites-stats').show(); + // $('#profile-following-stats').show(); + // $('#profile-favorites-stats').show(); $('#btn-add-friend').hide(); - $('#profile-social-left').hide(); + $('.profile-social-left').hide(); $('#profile-type-label').text('fan'); $('#profile-location-label').text('Presence'); } + + if (isCurrentUser()) { + $('#btn-profile-edit').show(); + } else { + $('#btn-profile-edit').hide(); + } } /****************** MAIN PORTION OF SCREEN *****************/ // events for main screen function events() { + configureUserType(); + // wire up panel clicks $('#profile-about-link').click(renderAbout); $('#profile-history-link').click(renderHistory); @@ -120,14 +132,12 @@ $('#profile-favorites-link').click(renderFavorites); // wire up buttons if you're not viewing your own profile - if (userId != context.JK.currentUserId) { + if (!isCurrentUser()) { // wire up Add Friend click - var friend = isFriend(); - configureFriendButton(friend); + configureFriendButton(isFriend()); // wire up Follow click - var following = isFollowing(); - configureFollowingButton(following); + configureFollowingButton(isFollowing()); } else { $('#btn-add-friend').hide(); @@ -248,6 +258,10 @@ } } + function configureEditProfileButton() { + $('#btn-follow-user').click(addFollowing); + } + // refreshes the currently active tab function renderActive() { if ($('#profile-about-link').hasClass('active')) { @@ -287,7 +301,6 @@ $('#profile-instruments').empty(); if (getUser()) { - configUserType(); // name $('#profile-username').html(user.name); @@ -325,7 +338,7 @@ text = user.follower_count > 1 || user.follower_count === 0 ? " Followers" : " Follower"; $('#profile-follower-stats').html(user.follower_count + text); - if (user.musician === true) { + if (isMusician()) { text = user.session_count > 1 || user.session_count === 0 ? " Sessions" : " Session"; $('#profile-session-stats').html(user.session_count + text); @@ -334,6 +347,8 @@ } else { text = " Following"; $('#profile-following-stats').html(user.following_count + text); + text = user.favorite_count > 1 || user.favorite_count === 0 ? " Favorites" : " Favorite"; + $('#profile-favorite-stats').html(user.favorite_count + text); } $('#profile-biography').html(user.biography); @@ -358,6 +373,12 @@ $('.profile-nav a.active').removeClass('active'); $('.profile-nav a.#profile-social-link').addClass('active'); + /*if (isMusician()) { + $('.profile-social-left').show(); + } else { + $('.profile-social-left').hide(); + }*/ + bindSocial(); } @@ -501,7 +522,7 @@ async: false, processData:false, success: function(response) { - if ( (!response || response.length === 0) && context.JK.currentUserId === userId) { + if ( (!response || response.length === 0) && isCurrentUser()) { var noBandHtml = $('#template-no-bands').html(); $("#profile-bands").append(noBandHtml); } @@ -567,7 +588,7 @@ } function addMoreBandsLink() { - if (context.JK.currentUserId === userId) { + if (isCurrentUser()) { var moreBandsHtml = $('#template-more-bands').html(); $("#profile-bands").append(moreBandsHtml); } diff --git a/web/app/controllers/api_users_controller.rb b/web/app/controllers/api_users_controller.rb index 40a96b869..1fa1c4271 100644 --- a/web/app/controllers/api_users_controller.rb +++ b/web/app/controllers/api_users_controller.rb @@ -19,7 +19,10 @@ class ApiUsersController < ApiController end def show - @user = User.find(params[:id]) + @user = User.includes([{:musician_instruments => :instrument}, + {:band_musicians => :user}, + :bands, :instruments]) + .find(params[:id]) respond_with @user, responder: ApiResponder, :status => 200 end diff --git a/web/app/views/api_users/show.rabl b/web/app/views/api_users/show.rabl index 4c63e2c39..13360ac19 100644 --- a/web/app/views/api_users/show.rabl +++ b/web/app/views/api_users/show.rabl @@ -1,6 +1,6 @@ object @user -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, :band_like_count, :follower_count, :following_count, :band_following_count, :recording_count, :session_count, :biography +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, :band_like_count, :follower_count, :following_count, :band_following_count, :recording_count, :session_count, :biography, :favorite_count if @user.musician? node :location do @user.location end diff --git a/web/app/views/clients/_account.html.erb b/web/app/views/clients/_account.html.erb index 0bd1a893c..526d56727 100644 --- a/web/app/views/clients/_account.html.erb +++ b/web/app/views/clients/_account.html.erb @@ -75,6 +75,8 @@

+ + <% if current_user && current_user.musician? %>
+ <% end %> + diff --git a/web/app/views/clients/_profile.html.erb b/web/app/views/clients/_profile.html.erb index 84b4ae9fe..5586c9546 100644 --- a/web/app/views/clients/_profile.html.erb +++ b/web/app/views/clients/_profile.html.erb @@ -23,6 +23,7 @@
ADD FRIEND FOLLOW + <%= link_to("EDIT PROFILE", '/client#/account/profile', :id => "btn-profile-edit", :class => "button-orange") %>


@@ -53,6 +54,7 @@


+


diff --git a/web/app/views/users/_user_dropdown.html.erb b/web/app/views/users/_user_dropdown.html.erb index ef6b4eed9..558e8d25c 100644 --- a/web/app/views/users/_user_dropdown.html.erb +++ b/web/app/views/users/_user_dropdown.html.erb @@ -18,8 +18,10 @@
  • <%= link_to "Profile", '/client#/account/profile' %>
  • -
  • <%= link_to "Audio Gear", '/client#/account/audio' %>
  • -
  • <%= link_to "Band Setup", '/client#/band/setup' %>
  • + <% if current_user && current_user.musician? %> +
  • <%= link_to "Audio Gear", '/client#/account/audio' %>
  • +
  • <%= link_to "Band Setup", '/client#/band/setup' %>
  • + <% end %>
  • <%= link_to "Invite Friends", '#' %>
    • <%= link_to "Google", '#' %>
    • @@ -37,4 +39,4 @@ <% end %> - \ No newline at end of file + From 9c6ccee6f0aa4abb9fd5cc21dd43e112afe5923d Mon Sep 17 00:00:00 2001 From: Daniel Weigh Date: Fri, 20 Dec 2013 07:04:58 -0500 Subject: [PATCH 40/40] VRFS-294 Adjustments to HTML/ CSS. --- web/app/assets/javascripts/findMusician.js | 4 +- .../assets/stylesheets/client/common.css.scss | 3 + .../stylesheets/client/content-orig.css.scss | 382 ++++++++++++++++++ .../stylesheets/client/content.css.scss | 159 +++++--- .../stylesheets/client/createSession.css.scss | 18 +- .../stylesheets/client/musician.css.scss | 31 +- .../stylesheets/client/profile.css.scss | 6 +- .../assets/stylesheets/client/search.css.scss | 4 +- web/app/views/clients/_account.html.erb | 220 +++++----- .../clients/_account_audio_profile.html.erb | 4 +- .../views/clients/_account_identity.html.erb | 4 +- .../views/clients/_account_profile.html.erb | 4 +- web/app/views/clients/_band_setup.html.erb | 235 +++++------ web/app/views/clients/_bands.html.erb | 12 +- web/app/views/clients/_createSession.html.erb | 294 +++++++------- web/app/views/clients/_feed.html.erb | 18 +- web/app/views/clients/_findSession.html.erb | 68 ++-- .../views/clients/_musician_filter.html.erb | 46 ++- web/app/views/clients/_musicians.html.erb | 26 +- web/app/views/clients/_profile.html.erb | 161 ++++---- web/app/views/clients/_web_filter.html.erb | 58 ++- 21 files changed, 1107 insertions(+), 650 deletions(-) create mode 100644 web/app/assets/stylesheets/client/content-orig.css.scss diff --git a/web/app/assets/javascripts/findMusician.js b/web/app/assets/javascripts/findMusician.js index 7c1e2e93a..7363ed50f 100644 --- a/web/app/assets/javascripts/findMusician.js +++ b/web/app/assets/javascripts/findMusician.js @@ -111,7 +111,7 @@ } var actionVals = { profile_url: "/#/profile/" + mm.id, - button_friend: mm['is_friend'] ? '' : 'button-orance', + button_friend: mm['is_friend'] ? '' : 'button-orange', button_follow: mm['is_following'] ? '' : 'button-orange', button_message: 'button-orange' }; @@ -233,4 +233,4 @@ return this; }; -})(window,jQuery); \ No newline at end of file +})(window,jQuery); diff --git a/web/app/assets/stylesheets/client/common.css.scss b/web/app/assets/stylesheets/client/common.css.scss index c75f35e17..67a0950f3 100644 --- a/web/app/assets/stylesheets/client/common.css.scss +++ b/web/app/assets/stylesheets/client/common.css.scss @@ -34,5 +34,8 @@ $text: #f3f1ee; $gradient-diff: 30%; $link: $color8; $border: hsl(210, 50%, 45%); +$narrow-screen: 1000px; // 990 ? 1000 ? +$short-screen: 600px; // toolbars / chrome for x768 + diff --git a/web/app/assets/stylesheets/client/content-orig.css.scss b/web/app/assets/stylesheets/client/content-orig.css.scss new file mode 100644 index 000000000..039a9e928 --- /dev/null +++ b/web/app/assets/stylesheets/client/content-orig.css.scss @@ -0,0 +1,382 @@ +/* This is simply Jeff's content.css file */ +@charset "UTF-8"; +#content { + background-color: #353535; + border: 1px solid #ed3618; + clear: both; + float: left; + margin-top: 39px; + height: auto; + width: auto; + position:relative; + padding-bottom:3px; +} + +.content-head { + height:21px; + padding:4px; + background-color:#ED3618; +} + +.content-icon { + margin-right:10px; + float:left; +} + +.content-head h1 { + margin: -6px 0px 0px 0px; + padding:0; + float:left; + font-weight:100; + font-size:24px; +} + +.content-nav { + float:right; + margin-right:10px; +} + +.home-icon { + float:left; + margin-right:20px; +} + +.content-nav a.arrow-right { + float:left; + display:block; + margin-top:2px; + margin-right:10px; + width: 0; + height: 0; + border-top: 7px solid transparent; + border-bottom: 7px solid transparent; + border-left: 7px solid #FFF; +} + +.content-nav a.arrow-left { + float:left; + display:block; + margin-top:2px; + margin-right:20px; + width: 0; + height: 0; + border-top: 7px solid transparent; + border-bottom: 7px solid transparent; + border-right:7px solid #FFF; +} + +#content-scroller, .content-scroller { + height:inherit; + position:relative; + display:block; + overflow:auto; +} + +.content-wrapper { + padding:10px 30px 10px 36px; + font-size:15px; + color:#ccc; + border-bottom: dotted 1px #444; + overflow-x:hidden; + white-space:nowrap; +} + +.create-session-left { + width:50%; + float:left; +} + +.create-session-right { + width:45%; + float:right; + font-size:13px; +} + +.content-wrapper h2 { + color:#fff; + font-weight:600; + font-size:24px; +} + +.content-wrapper select, .content-wrapper textarea, .content-wrapper input[type=text], .content-wrapper input[type=password], div.friendbox, .ftue-inner input[type=text], .ftue-inner input[type=password], .dialog-inner textarea, .dialog-inner input[type=text] { + font-family:"Raleway", arial, sans-serif; + background-color:#c5c5c5; + border:none; + -webkit-box-shadow: inset 2px 2px 3px 0px #888; + box-shadow: inset 2px 2px 3px 0px #888; + color:#666; +} + +.create-session-description { + padding:5px; + width:100%; + height:80px; +} + +.friendbox { + padding:5px; + width:100%; + height:60px; +} + +.invite-friend { + margin:0px 4px 4px 4px; + float:left; + display:block; + background-color:#666; + color:#fff; + font-size:12px; + -webkit-border-radius: 7px; + border-radius: 7px; + padding:2px 2px 2px 4px; +} + +.content-wrapper div.friendbox input[type=text] { + -webkit-box-shadow: inset 0px 0px 0px 0px #888; + box-shadow: inset 0px 0px 0px 0px #888; + color:#666; + font-style:italic; +} + +#genrelist, #musicianlist { + position:relative; + z-index:99; + width: 175px; + -webkit-border-radius: 6px; + border-radius: 6px; + background-color:#C5C5C5; + border: none; + color:#333; + font-weight:400; + padding:0px 0px 0px 8px; + height:20px; + line-height:20px; + overflow:hidden; + -webkit-box-shadow: inset 2px 2px 3px 0px #888; + box-shadow: inset 2px 2px 3px 0px #888; +} + +#musicianlist, .session-controls #genrelist { + width: 150px; +} + +#genrelist a, #musicianlist a { + color:#333; + text-decoration:none; +} + +.genre-wrapper, .musician-wrapper { + float:left; + width:175px; + height:127px; + overflow:auto; +} + +.musician-wrapper, .session-controls .genre-wrapper { + width:150px; +} + +.genrecategory { + font-size:11px; + float:left; + width:135px; +} + +.filtercategory, .session-controls .genrecategory { + font-size:11px; + float:left; + width:110px; +} + +a.arrow-up { + float:right; + margin-right:5px; + display:block; + margin-top:6px; + width: 0; + height: 0; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #333; +} + +a.arrow-down { + float:right; + margin-right:5px; + display:block; + margin-top:6px; + width: 0; + height: 0; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-top: 7px solid #333; +} + +.settings-session-description { + padding:10px; + width:300px; +} + +#session-controls { + width:100%; + padding:11px 0px 11px 0px; + background-color:#4c4c4c; + min-height:20px; + overflow-x:hidden; + } + +#session-controls .searchbox { + float:left; + width:140px; + margin-left: 10px; + -webkit-border-radius: 6px; + border-radius: 6px; + background-color:#C5C5C5; + border: none; + color:#333; + font-weight:400; + padding:0px 0px 0px 8px; + height:20px; + line-height:20px; + overflow:hidden; + -webkit-box-shadow: inset 2px 2px 3px 0px #888; + box-shadow: inset 2px 2px 3px 0px #888; +} + +#session-controls input[type=text] { + background-color:#c5c5c5; + border:none; + color:#666; +} + +.avatar-tiny { + float:left; + padding:1px; + width:24px; + height:24px; + background-color:#ed3618; + -webkit-border-radius:12px; + -moz-border-radius:12px; + border-radius:12px; +} + +.ftue-background { + background-image:url(../images/content/bkg_ftue.jpg); + background-repeat:no-repeat; + background-size:cover; + min-height:475px; + min-width:672px; +} + +table.generaltable { + background-color: #262626; + border: 1px solid #4D4D4D; + color: #FFFFFF; + font-size: 11px; + margin-top: 6px; + width: 100%; + + th { + background-color: #4D4D4D; + border-right: 1px solid #333333; + font-weight: 300; + padding: 6px; + } + + td { + border-right: 1px solid #333333; + border-top: 1px solid #333333; + padding: 9px 5px 5px; + vertical-align: top; + white-space: normal; + } + + .noborder { + border-right: medium none; + } +} + +ul.shortcuts { + border:1px solid #ED3618; + + li { + margin:0; + height:20px; + line-height:20px; + padding:2px; + } + + .account-home, .band-setup, .audio, .get-help, .download-app, .invite-friends { + border-bottom:1px; + border-style:solid; + border-color:#ED3618; + } + + span.arrow-right { + display:inline-block; + width: 0; + height: 0; + border-top: 4px solid transparent; + border-bottom: 4px solid transparent; + border-left: 4px solid #FFCC00; + padding-left:5px; + } + + ul.shortcuts-submenu { + display:none; + + li { + margin:0; + height:20px; + line-height:20px; + padding:2px; + color:#FFCC00; + } + + li.google-invite, li.email-invite { + padding-left:9px; + } + + } +} + +.tagline { + font-size:30px; + margin-top:35px; + color:#ed3718; + font-weight:300; + width:345px; + clear:left; + white-space:normal; +} + +.smallbutton { + font-size:10px !important; + padding:2px 8px !important; +} + +.whitespace { + white-space:normal; +} + +.w0 {width:0% !important} +.w5 {width:5% !important} +.w10 {width:10% !important} +.w15 {width:15% !important} +.w20 {width:20% !important} +.w25 {width:25% !important} +.w30 {width:30% !important} +.w35 {width:35% !important} +.w40 {width:40% !important} +.w45 {width:45% !important} +.w50 {width:50% !important} +.w55 {width:55% !important} +.w60 {width:60% !important} +.w65 {width:65% !important} +.w70 {width:70% !important} +.w75 {width:75% !important} +.w80 {width:80% !important} +.w85 {width:85% !important} +.w90 {width:90% !important} +.w95 {width:95% !important} +.w100 {width:100% !important} diff --git a/web/app/assets/stylesheets/client/content.css.scss b/web/app/assets/stylesheets/client/content.css.scss index 2c7d100e8..44fa0178e 100644 --- a/web/app/assets/stylesheets/client/content.css.scss +++ b/web/app/assets/stylesheets/client/content.css.scss @@ -1,5 +1,7 @@ -/* This is simply Jeff's content.css file */ -@charset "UTF-8"; +/* This is Daniel's content.css file */ +/* Common styles used in screens */ +@import "client/common.css.scss";@charset "UTF-8"; + #content { background-color: #353535; border: 1px solid #ed3618; @@ -12,58 +14,96 @@ padding-bottom:3px; } -.content-head { - height:21px; - padding:4px; - background-color:#ED3618; +/* Daniel's tweaks */ +.screen, .screen .content { + .content-head { + position: absolute; + height:21px; + padding:4px 0; + width:100%; + background-color:$ColorScreenPrimary; + + .content-icon { + margin: -1px 10px 0 4px; + float:left; + } + + .content-nav { + float:right; + margin-right:10px; + + a { + &.arrow-right, + &.arrow-left { + float:left; + display:block; + margin-top:2px; + width: 0; + height: 0; + border-top: 7px solid transparent; + border-bottom: 7px solid transparent; + } + &.arrow-right { + margin-right:10px; + border-left: 7px solid #FFF; + } + &.arrow-left { + margin-right:20px; + border-right:7px solid #FFF; + } + + } + } + + h1 { + margin: -3px 0px 0px 0px; + padding:0; + float:left; + font-weight:100; + font-size:24px; + } + } + .content-body { + height:100%; + width:100%; + box-sizing: border-box; + padding-top: 29px; + + .content-body-scroller { + height:inherit; + position:relative; + display:block; + overflow:auto; +// padding: 10px 35px; + + @media screen and (max-width: $narrow-screen) { +// padding: 10px 20px; + } + + &.outer { + overflow: hidden; + > * { + height:inherit; + } + } + } + } } -.content-icon { - margin-right:10px; - float:left; +.result-list-button-wrapper { + margin-top: 10px; + margin-bottom: 10px; + > a.smallbutton { + margin: 2px; + } } -.content-head h1 { - margin: -6px 0px 0px 0px; - padding:0; - float:left; - font-weight:100; - font-size:24px; -} - -.content-nav { - float:right; - margin-right:10px; -} .home-icon { float:left; margin-right:20px; } -.content-nav a.arrow-right { - float:left; - display:block; - margin-top:2px; - margin-right:10px; - width: 0; - height: 0; - border-top: 7px solid transparent; - border-bottom: 7px solid transparent; - border-left: 7px solid #FFF; -} - -.content-nav a.arrow-left { - float:left; - display:block; - margin-top:2px; - margin-right:20px; - width: 0; - height: 0; - border-top: 7px solid transparent; - border-bottom: 7px solid transparent; - border-right:7px solid #FFF; -} #content-scroller, .content-scroller { height:inherit; @@ -72,25 +112,14 @@ overflow:auto; } -.content-wrapper { - padding:10px 30px 10px 36px; - font-size:15px; - color:#ccc; - border-bottom: dotted 1px #444; - overflow-x:hidden; - white-space:nowrap; -} - -.create-session-left { - width:50%; - float:left; -} - -.create-session-right { - width:45%; - float:right; - font-size:13px; -} +//.content-wrapper { +// padding:10px 30px 10px 36px; +// font-size:15px; +// color:#ccc; +// border-bottom: dotted 1px #444; +// overflow-x:hidden; +// white-space:nowrap; +//} .content-wrapper h2 { color:#fff; @@ -222,7 +251,7 @@ a.arrow-down { padding:11px 0px 11px 0px; background-color:#4c4c4c; min-height:20px; - overflow-x:hidden; + overflow-x:scroll; } #session-controls .searchbox { @@ -379,4 +408,4 @@ ul.shortcuts { .w85 {width:85% !important} .w90 {width:90% !important} .w95 {width:95% !important} -.w100 {width:100% !important} \ No newline at end of file +.w100 {width:100% !important} diff --git a/web/app/assets/stylesheets/client/createSession.css.scss b/web/app/assets/stylesheets/client/createSession.css.scss index a14c37c67..f345b2ac4 100644 --- a/web/app/assets/stylesheets/client/createSession.css.scss +++ b/web/app/assets/stylesheets/client/createSession.css.scss @@ -1,25 +1,9 @@ -.create-session { - .content { - .content-head { - position:absolute; - z-index:1; - padding: 4px 0; - width:100%; - - .content-icon { - margin-left:4px; - } - } - } -} - .session-wrapper { - padding: 29px 35px 10px; + padding: 10px 35px; white-space: initial; > div.session { width: 50%; - padding-top: 10px; &.right { font-size: 13px; diff --git a/web/app/assets/stylesheets/client/musician.css.scss b/web/app/assets/stylesheets/client/musician.css.scss index 709fc7f0b..fc78eefa3 100644 --- a/web/app/assets/stylesheets/client/musician.css.scss +++ b/web/app/assets/stylesheets/client/musician.css.scss @@ -1,18 +1,35 @@ .filter-element { float:left; margin-left: 5px; + + &.wrapper { + margin-top: 5px; + &.right { + float: right; + > a { + margin-top: 3px; + } + } + } + + // @FIXME labeel is overriding from #session-controls. + &.desc { + margin-top: 3px; + padding-top: 3px; + } } + #musician-filter-results { - margin: 0 10px 5px 10px; + margin: 0 10px 0px 10px; overflow: auto; height: 100%; - width: 100%; +// width: 100%; } .musician-wrapper { - overflow: auto; - height: 480px; +// overflow: auto; +// height: 480px; width: 100%; } @@ -20,8 +37,12 @@ padding-top: 5px; padding-right: 5px; padding-left: 5px; + box-sizing:border-box; } +#session-controls.musician-filter { + padding-top: 6px; +} .musician-following { overflow: auto; -} \ No newline at end of file +} diff --git a/web/app/assets/stylesheets/client/profile.css.scss b/web/app/assets/stylesheets/client/profile.css.scss index c7f543555..ef0a772dd 100644 --- a/web/app/assets/stylesheets/client/profile.css.scss +++ b/web/app/assets/stylesheets/client/profile.css.scss @@ -1,8 +1,8 @@ @import "client/common.css.scss"; .profile-header { - padding:20px; - height:120px; + padding:10px 20px; +// height:120px; } .profile-header h2 { @@ -252,4 +252,4 @@ border-top:none; padding:3px; vertical-align:middle; -} \ No newline at end of file +} diff --git a/web/app/assets/stylesheets/client/search.css.scss b/web/app/assets/stylesheets/client/search.css.scss index 352a3b644..c1a43fe51 100644 --- a/web/app/assets/stylesheets/client/search.css.scss +++ b/web/app/assets/stylesheets/client/search.css.scss @@ -57,8 +57,8 @@ .query-distance-params { float: left; - width: 80px; - margin-left: 10px; +// width: 80px; + margin-left: 2px; border: none; } diff --git a/web/app/views/clients/_account.html.erb b/web/app/views/clients/_account.html.erb index 526d56727..86c8f43d8 100644 --- a/web/app/views/clients/_account.html.erb +++ b/web/app/views/clients/_account.html.erb @@ -1,115 +1,117 @@ +
      -
      - -
      -
      - <%= image_tag "content/icon_account.png", {:height => 18, :width => 18} %> +
      + +
      +
      + <%= image_tag "content/icon_account.png", {:height => 18, :width => 18} %> +
      +

      my account

      + <%= render "screen_navigation" %> +
      + + +
      + + +
      -

      my account

      - <%= render "screen_navigation" %>
      - - - - - diff --git a/web/app/views/clients/_account_audio_profile.html.erb b/web/app/views/clients/_account_audio_profile.html.erb index 236bd2c8b..d1e5fc947 100644 --- a/web/app/views/clients/_account_audio_profile.html.erb +++ b/web/app/views/clients/_account_audio_profile.html.erb @@ -13,8 +13,10 @@ - diff --git a/web/app/views/clients/_account_identity.html.erb b/web/app/views/clients/_account_identity.html.erb index f99233cce..345825c42 100644 --- a/web/app/views/clients/_account_identity.html.erb +++ b/web/app/views/clients/_account_identity.html.erb @@ -13,8 +13,10 @@ - diff --git a/web/app/views/clients/_account_profile.html.erb b/web/app/views/clients/_account_profile.html.erb index 69e6903cc..e301ae4e5 100644 --- a/web/app/views/clients/_account_profile.html.erb +++ b/web/app/views/clients/_account_profile.html.erb @@ -13,8 +13,10 @@ - diff --git a/web/app/views/clients/_band_setup.html.erb b/web/app/views/clients/_band_setup.html.erb index ab8e9e77a..6cc1b644e 100644 --- a/web/app/views/clients/_band_setup.html.erb +++ b/web/app/views/clients/_band_setup.html.erb @@ -9,126 +9,127 @@ <%= render "screen_navigation" %>
      -
      -
      - -
      - -
      +
      - - +
      \ No newline at end of file + diff --git a/web/app/views/clients/_bands.html.erb b/web/app/views/clients/_bands.html.erb index 473ecf9bf..6e82eb331 100644 --- a/web/app/views/clients/_bands.html.erb +++ b/web/app/views/clients/_bands.html.erb @@ -6,10 +6,14 @@ <%= content_tag(:h1, 'bands') %> <%= render "screen_navigation" %> <% end -%> - <%= form_tag('', :id => 'find-band-form') do -%> - <%= content_tag(:div, render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_BAND}), :class => 'band-filter', :id => 'session-controls') %> - <%= content_tag(:div, :class => 'content-scroller') do -%> - <%= content_tag(:div, content_tag(:div, '', :id => 'band-filter-results', :class => 'filter-results'), :class => 'content-wrapper band-wrapper') %> + <%= content_tag(:div, :class => 'content-body') do -%> + <%= content_tag(:div, :class => 'content-body-scroller') do -%> + <%= form_tag('', :id => 'find-band-form') do -%> + <%= content_tag(:div, render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_BAND}), :class => 'band-filter', :id => 'session-controls') %> + <%= content_tag(:div, :class => 'content-scroller') do -%> + <%= content_tag(:div, content_tag(:div, '', :id => 'band-filter-results', :class => 'filter-results'), :class => 'content-wrapper band-wrapper') %> + <% end -%> + <% end -%> <% end -%> <% end -%> <% end -%> diff --git a/web/app/views/clients/_createSession.html.erb b/web/app/views/clients/_createSession.html.erb index 406e50a9d..114bcaf86 100644 --- a/web/app/views/clients/_createSession.html.erb +++ b/web/app/views/clients/_createSession.html.erb @@ -9,160 +9,164 @@

      create session

      <%= render "screen_navigation" %> +
      -
      -
      -
      - -
      -
      +
      +
      + +
      + +
      +
      -

      session info

      -
      +

      session info

      +
      -
      -
      Description:
      -
      - -
      -
      - -
      -
      Genre:
      -
      - <%= render "genreSelector" %> -
      -
      - -
      -
      Band:
      -
      - -
      -
      - -

      - -
      Musician Access:
      -
      -
      - -
      - -
      - - -
      -
      - -

      - -
      Fan Access:
      -
      -
      - -
      - -
      - - -
      -
      -
      - -
      -

      invite musicians

      - -
      -
      - -
      - Start typing friends' names or: -
      -
      -
      -
      - - -
      -
      - -
      - -
      - Invite friends and contacts to join you on JamKazam from: -
      -
      - - - - -
      -
      -
      - -
      -
      - -
      -
      - I agree that intellectual property ownership of any musical works created during this session shall be governed by the terms of the Creative Commons CC BY-NC-SA license in accordance with the JamKazam Terms of Service. -
      -
      -
      -
      -
      +
      +
      Description:
      - CANCEL - JAM! + +
      +
      + +
      +
      Genre:
      +
      + <%= render "genreSelector" %> +
      +
      + +
      +
      Band:
      +
      + +
      +
      + +

      + +
      Musician Access:
      +
      +
      + +
      + +
      + + +
      +
      + +

      + +
      Fan Access:
      +
      +
      + +
      + +
      + +
      + +
      +

      invite musicians

      + +
      +
      + +
      + Start typing friends' names or: +
      +
      +
      +
      + + +
      +
      + +
      + +
      + Invite friends and contacts to join you on JamKazam from: +
      +
      + + + + +
      +
      +
      + +
      +
      + +
      +
      + I agree that intellectual property ownership of any musical works created during this session shall be governed by the terms of the Creative Commons CC BY-NC-SA license in accordance with the JamKazam Terms of Service. +
      +
      +
      +
      +
      +
      + CANCEL + JAM! +
      +
      +
      +
      +
      -
      -
      - + +
      +
      diff --git a/web/app/views/clients/_feed.html.erb b/web/app/views/clients/_feed.html.erb index 5f09c1720..80b2a24b1 100644 --- a/web/app/views/clients/_feed.html.erb +++ b/web/app/views/clients/_feed.html.erb @@ -1,12 +1,18 @@
      -
      +
      +
      -
      - <%= image_tag "content/icon_feed.png", {:height => 19, :width => 19} %> +
      + <%= image_tag "content/icon_feed.png", {:height => 19, :width => 19} %> +
      +

      feed

      + <%= render "screen_navigation" %> +
      +
      +
      +

      This feature not yet implemented

      +
      -

      feed

      - <%= render "screen_navigation" %>
      -

      This feature not yet implemented

      diff --git a/web/app/views/clients/_findSession.html.erb b/web/app/views/clients/_findSession.html.erb index af1d851c6..dc8a54bfb 100644 --- a/web/app/views/clients/_findSession.html.erb +++ b/web/app/views/clients/_findSession.html.erb @@ -10,43 +10,47 @@ <%= render "screen_navigation" %>
      -
      -
      -
      -
      Filter Session List:
      +
      +
      + +
      +
      +
      Filter Session List:
      - -
      - <%= render "genreSelector" %> -
      + +
      + <%= render "genreSelector" %> +
      - -
      -
      - REFRESH +
      +
      +
      + <%= render :partial => "sessionList", :locals => {:title => "sessions you're invited to", :category => "sessions-invitations"} %> +
      +
      + <%= render :partial => "sessionList", :locals => {:title => "sessions with friends or bandmates", :category => "sessions-friends"} %> +
      +
      + <%= render :partial => "sessionList", :locals => {:title => "other sessions", :category => "sessions-other"} %> +
      +
      + + + +
      + There are currently no public sessions.
      -
      -
      -
      - <%= render :partial => "sessionList", :locals => {:title => "sessions you're invited to", :category => "sessions-invitations"} %> -
      -
      - <%= render :partial => "sessionList", :locals => {:title => "sessions with friends or bandmates", :category => "sessions-friends"} %> -
      -
      - <%= render :partial => "sessionList", :locals => {:title => "other sessions", :category => "sessions-other"} %> -
      -
      -
      - - - -
      - There are currently no public sessions.
      @@ -105,4 +109,4 @@ \ No newline at end of file + diff --git a/web/app/views/clients/_musician_filter.html.erb b/web/app/views/clients/_musician_filter.html.erb index 917136950..f5650b65d 100644 --- a/web/app/views/clients/_musician_filter.html.erb +++ b/web/app/views/clients/_musician_filter.html.erb @@ -1,25 +1,29 @@ -<%= content_tag(:div, :style => "min-width:770px;") do -%> - <%= content_tag(:div, :class => 'filter-element') do -%> - <%= content_tag(:div, 'Filter By:', :class => 'filter-element', :style => "padding-top:3px;") %> - - <%= select_tag(:musician_order_by, options_for_select(Search::M_ORDERINGS), {:class => 'musician-order-by'} ) %> - <% end -%> - <%= content_tag(:div, :class => 'filter-element') do -%> +<%= content_tag(:div, :class => 'filter-element wrapper foobar') do -%> + <%= content_tag(:div, 'Filter By:', :class => 'filter-element desc') %> + + <%= select_tag(:musician_order_by, options_for_select(Search::M_ORDERINGS), {:class => 'musician-order-by'} ) %> +<% end -%> +<%= content_tag(:div, :class => "filter-element wrapper") do -%> + <%= content_tag(:div, :class => 'filter-element wrapper') do -%> - <%= content_tag(:div, 'Instrument:', :class => 'filter-element') %> - <%= content_tag(:div, :class => 'filter-element') do -%> - <%= select_tag(:musician_instrument, + <%= content_tag(:div, 'Instrumente:', :class => 'filter-element') %> + <%= select_tag(:musician_instrument, options_for_select([['Any', '']].concat(JamRuby::Instrument.all.collect { |ii| [ii.description, ii.id] }))) %> - <% end -%> - <% end -%> - - <%= content_tag(:div, :class => 'filter-element') do -%> - <%= content_tag(:div, 'Within', :class => 'filter-element') %> - <%= content_tag(:div, :class => 'query-distance-params') do -%> - <%= select_tag('musician_query_distance', options_for_select(Search::M_DISTANCE_OPTS, Search::M_MILES_DEFAULT)) %> - <% end -%> - <%= content_tag(:div, :class => 'filter-element') do -%> - miles of <%= content_tag(:span, current_user.current_city(request.remote_ip), :id => 'musician-filter-city') %> - <% end -%> <% end -%> <% end -%> + +<%= content_tag(:div, :class => 'filter-element wrapper') do -%> + <%= content_tag(:div, 'Within', :class => 'filter-element desc') %> + <%= content_tag(:div, :class => 'query-distance-params') do -%> + <%= select_tag('musician_query_distance', options_for_select(Search::M_DISTANCE_OPTS, Search::M_MILES_DEFAULT)) %> + <% end -%> + <%= content_tag(:div, :class => 'filter-element') do -%> + miles of <%= content_tag(:span, current_user.current_city(request.remote_ip), :id => 'musician-filter-city') %> + <% end -%> +<% end -%> +<%= content_tag(:div, +link_to('REFRESH', '#', + :id => 'btn-refresh-musicians', + :style => 'text-decoration:none', + :class => 'button-grey'), +:class => 'filter-element wrapper right mr10') %> diff --git a/web/app/views/clients/_musicians.html.erb b/web/app/views/clients/_musicians.html.erb index 973b93880..115aba151 100644 --- a/web/app/views/clients/_musicians.html.erb +++ b/web/app/views/clients/_musicians.html.erb @@ -6,10 +6,14 @@ <%= content_tag(:h1, 'musicians') %> <%= render "screen_navigation" %> <% end -%> - <%= form_tag('', :id => 'find-musician-form') do -%> - <%= content_tag(:div, render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_MUSICIAN}), :class => 'musician-filter', :id => 'session-controls') %> - <%= content_tag(:div, :class => 'content-scroller') do -%> - <%= content_tag(:div, content_tag(:div, '', :id => 'musician-filter-results'), :class => 'content-wrapper musician-wrapper') %> + <%= content_tag(:div, :class => 'content-body') do -%> + <%= content_tag(:div, :class => 'content-body-scroller') do -%> + <%= form_tag('', :id => 'find-musician-form') do -%> + <%= content_tag(:div, render(:partial => "web_filter", :locals => {:search_type => Search::PARAM_MUSICIAN}), :class => 'musician-filter', :id => 'session-controls') %> + <%= content_tag(:div, :class => 'content-scroller') do -%> + <%= content_tag(:div, content_tag(:div, '', :id => 'musician-filter-results'), :class => 'content-wrapper musician-wrapper') %> + <% end -%> + <% end -%> <% end -%> <% end -%> <% end -%> @@ -32,10 +36,10 @@

      - {biography}
      + {biography}

      -
      - {musician_action_template} +
      + {musician_action_template}
      @@ -48,7 +52,13 @@