Skip to content
This repository was archived by the owner on Dec 3, 2019. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ db_migrate:
db_rollback:
docker-compose run ${RAILS_CONTAINER} rake db:rollback

.PHONY: db_seed
db_seed:
docker-compose run ${RAILS_CONTAINER} rake db:seed

.PHONY: test
test: bg
docker-compose run operationcode-psql bash -c "while ! psql --host=operationcode-psql --username=postgres -c 'SELECT 1'; do sleep 5; done;"
Expand Down
9 changes: 8 additions & 1 deletion apiary.apib
Original file line number Diff line number Diff line change
Expand Up @@ -393,12 +393,13 @@ API endpoints that Operation Code's Rails backend makes available to its React f
errors: "Some error message"
}

## User | Count By Location [/api/v1/users/by_location{?zip,city,lat_long,radius}]
## User | Count By Location [/api/v1/users/by_location{?state,zip,city,lat_long,radius}]

### By Location [GET]

+ Parameters

+ state (string, optional) - String of comma-separated state abbreviations, i.e. 'TX', or 'TX, CA'
+ zip (string, optional) - String of comma-separated zip code(s), i.e. '80126', or '80126, 80203'
+ city (string, optional) - A string of a 'City, State, County' (i.e. 'Denver, CO, US')
+ lat_long (integer, optional) - Comma-separated integer latitude and longitude, i.e. 30.285648, -97.742052
Expand All @@ -408,6 +409,12 @@ API endpoints that Operation Code's Rails backend makes available to its React f

+ Body

{
state: 'TX, CA'
}

/*or*/

{
zip: '80126, 80203'
}
Expand Down
11 changes: 11 additions & 0 deletions app/lib/format_data.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class FormatData

# Converts a comma-separated string into an array of its contents.
#
# @param comma_separated_string [String] String of comma-separated values, i.e '80123, 80202'
# @return [Array] An array of strings, i.e. ['80123', '80202']
#
def self.csv_to_array(comma_separated_string)
comma_separated_string.split(',').map(&:strip)
end
end
5 changes: 4 additions & 1 deletion app/lib/users_by_location.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
class UsersByLocation
def initialize(params)
@state = params[:state]
@zip = params[:zip]
@city = params[:city]
@lat_long = params[:lat_long]
@radius = params[:radius] || 20
end

def count
if @zip.present?
if @state.present?
User.count_by_state @state
elsif @zip.present?
User.count_by_zip @zip
elsif @city.present?
User.count_by_location @city, @radius
Expand Down
20 changes: 18 additions & 2 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,32 @@ class User < ApplicationRecord

scope :mentors, -> { where(mentor: true) }
scope :by_zip, ->(zip) { where(zip: zip) }
scope :by_state, ->(state) { where(state: state) }

# Returns a count of all users with the passed in zip code(s)
#
# @param zip_codes [String] String of comma-separated zip code(s), i.e. '80126', or '80126, 80203'
# @return [Integer] A count of the requested users.
#
def self.count_by_zip(zip_codes)
return 0 unless zip_codes.present?

zips = zip_codes.split(',').map(&:strip)
zips = FormatData.csv_to_array(zip_codes)

by_zip(zips).count
self.by_zip(zips).count
end

# Returns a count of all users with the passed in state abbreviations.
#
# @param state_abbreviations [String] String of comma-separated state_abbreviations, i.e. 'CO', or 'CO, TX'
# @return [Integer] A count of the requested users.
#
def self.count_by_state(state_abbreviations)
return 0 unless state_abbreviations.present?

states = FormatData.csv_to_array(state_abbreviations)

self.by_state(states).count
end

# Returns a count of all users within the passed in location. The location can
Expand All @@ -48,6 +63,7 @@ def self.count_by_zip(zip_codes)
# @param location [String || Array] Either a 'City, State, County' or [Latitude, Longitude]
# For example, 'Denver, CO, US'.
# @param radius [Integer] Include results within the radius' distance from the location, in miles.
# @return [Integer] A count of the requested users.
# @see https://github.com/alexreisner/geocoder#for-activerecord-models
#
def self.count_by_location(location, radius=20)
Expand Down
16 changes: 12 additions & 4 deletions test/controllers/api/v1/users_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,16 @@ class Api::V1::UsersControllerTest < ActionDispatch::IntegrationTest
end

test ":by_location returns User.count of users located in the passed in location" do
tom = create :user, zip: '78705'
sam = create :user, zip: '78756'
tom = create :user
sam = create :user

tom.update latitude: 30.285648, longitude: -97.742052
sam.update latitude: 30.312601, longitude: -97.738591
tom.update_columns latitude: 30.285648, longitude: -97.742052, zip: '78705', state: 'TX'
sam.update_columns latitude: 30.312601, longitude: -97.738591, zip: '78756', state: 'TX'

params = { state: 'TX' }
get api_v1_users_by_location_url(params), headers: @headers, as: :json
assert_equal({ 'user_count' => 2 }, response.parsed_body)
assert_equal 200, response.status

params = { zip: '78705' }
get api_v1_users_by_location_url(params), as: :json
Expand All @@ -25,13 +30,16 @@ class Api::V1::UsersControllerTest < ActionDispatch::IntegrationTest
params = { zip: '78705, 78756' }
get api_v1_users_by_location_url(params), as: :json
assert_equal({ 'user_count' => 2 }, response.parsed_body)
assert_equal 200, response.status

params = { lat_long: [30.285648, -97.742052] }
get api_v1_users_by_location_url(params), as: :json
assert_equal({ 'user_count' => 2 }, response.parsed_body)
assert_equal 200, response.status

params = { lat_long: [30.285648, -97.742052], radius: 1 }
get api_v1_users_by_location_url(params), as: :json
assert_equal({ 'user_count' => 1 }, response.parsed_body)
assert_equal 200, response.status
end
end
14 changes: 14 additions & 0 deletions test/lib/format_data_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require 'test_helper'

class FormatDataTest < ActiveSupport::TestCase
test '.csv_to_array' do
results = FormatData.csv_to_array '80202'
assert_equal ['80202'], results

results = FormatData.csv_to_array '80202, 80126'
assert_equal ['80202', '80126'], results

results = FormatData.csv_to_array 'TX, MN'
assert_equal ['TX', 'MN'], results
end
end
50 changes: 50 additions & 0 deletions test/lib/users_by_location_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
require 'test_helper'

class UsersByLocationTest < ActiveSupport::TestCase
setup do
tom = create :user
sam = create :user

tom.update_columns latitude: 39.763034, longitude: -104.961969, zip: '80205', state: 'CO'
sam.update_columns latitude: 30.312601, longitude: -97.738591, zip: '78756', state: 'TX'
end

test '#count by state' do
params = { state: 'CO' }
results = UsersByLocation.new(params).count
assert_equal 1, results

params = { state: 'TX' }
results = UsersByLocation.new(params).count
assert_equal 1, results

params = { state: 'CO, TX' }
results = UsersByLocation.new(params).count
assert_equal 2, results
end

test '#count by zip' do
params = { zip: '80205' }
results = UsersByLocation.new(params).count
assert_equal 1, results

params = { zip: '78756' }
results = UsersByLocation.new(params).count
assert_equal 1, results

params = { zip: '80205, 78756' }
results = UsersByLocation.new(params).count
assert_equal 2, results
end

test '#count by lat_long' do
params = { lat_long: [39.763034, -104.961969] }
results = UsersByLocation.new(params).count
assert_equal 1, results

params = { lat_long: [30.312601, -97.738591] }
results = UsersByLocation.new(params).count
assert_equal 1, results
end
end

19 changes: 19 additions & 0 deletions test/models/user_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,23 @@ def stub_geocoder
test 'it returns a users full name' do
assert_equal 'first last', User.new(first_name: 'first', last_name: 'last').name
end

test '.count_by_state returns a count of all users within the passed in state(s)' do
tom = create :user
sam = create :user
bob = create :user

tom.update_columns state: 'TX'
sam.update_columns state: 'TX'
bob.update_columns state: 'CA'

results = User.count_by_state 'TX'
assert_equal 2, results

results = User.count_by_state 'TX, CA'
assert_equal 3, results

results = User.count_by_state ''
assert_equal 0, results
end
end