* VRFS-1403 - maxmind single step import done

This commit is contained in:
Seth Call 2014-07-19 21:11:16 -05:00
parent ae8c3120aa
commit 5f131f9407
68 changed files with 1528 additions and 750 deletions

View File

@ -121,5 +121,9 @@ module JamAdmin
config.ffmpeg_path = ENV['FFMPEG_PATH'] || (File.exist?('/usr/local/bin/ffmpeg') ? '/usr/local/bin/ffmpeg' : '/usr/bin/ffmpeg') config.ffmpeg_path = ENV['FFMPEG_PATH'] || (File.exist?('/usr/local/bin/ffmpeg') ? '/usr/local/bin/ffmpeg' : '/usr/bin/ffmpeg')
config.max_audio_downloads = 100 config.max_audio_downloads = 100
# recording upload/download configs
config.max_track_upload_failures = 10
config.max_track_part_upload_failures = 3
end end
end end

View File

@ -17,4 +17,4 @@ mkdir -p /var/log/$NAME
chown -R $USER:$GROUP /var/lib/$NAME chown -R $USER:$GROUP /var/lib/$NAME
chown -R $USER:$GROUP /etc/$NAME chown -R $USER:$GROUP /etc/$NAME
chown -R $USER:$GROUP /var/log/$NAME chown -R $USER:$GROUP /var/log/$NAME

View File

@ -2,7 +2,7 @@ ALTER TABLE users ADD COLUMN last_jam_addr BIGINT;
ALTER TABLE users ADD COLUMN last_jam_locidispid BIGINT; ALTER TABLE users ADD COLUMN last_jam_locidispid BIGINT;
-- (j)oin session as musician, (r)egister, (f)tue, (n)etwork test -- (j)oin session as musician, (r)egister, (f)tue, (n)etwork test, maxmind (i)mport
ALTER TABLE users ADD COLUMN last_jam_updated_reason CHAR(1); ALTER TABLE users ADD COLUMN last_jam_updated_reason CHAR(1);
ALTER TABLE users ADD COLUMN last_jam_updated_at TIMESTAMP; ALTER TABLE users ADD COLUMN last_jam_updated_at TIMESTAMP;

View File

@ -1,27 +1,45 @@
-- released_at is when maxmind released this data -- released_at is when maxmind released this data
CREATE TABLE max_mind_releases ( CREATE TABLE max_mind_releases (
id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(), id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(),
released_at DATE, released_at DATE UNIQUE NOT NULL,
imported BOOLEAN NOT NULL DEFAULT FALSE,
imported_at DATE,
geo_ip_124_url VARCHAR(2000), geo_ip_124_url VARCHAR(2000),
geo_ip_124_md5 VARCHAR(255), geo_ip_124_md5 VARCHAR(255),
geo_ip_124_size INTEGER, geo_ip_124_size INTEGER,
geo_ip_134_url VARCHAR(2000), geo_ip_134_url VARCHAR(2000),
geo_ip_134_md5 VARCHAR(255), geo_ip_134_md5 VARCHAR(255),
geo_ip_134_size INTEGER, geo_ip_134_size INTEGER,
geo_ip_139_url VARCHAR(2000), region_codes_url VARCHAR(2000),
geo_ip_139_md5 VARCHAR(255), region_codes_md5 VARCHAR(255),
geo_ip_139_size INTEGER, region_codes_size INTEGER,
geo_ip_142_url VARCHAR(2000), iso3166_url VARCHAR(2000),
geo_ip_142_md5 VARCHAR(255), iso3166_md5 VARCHAR(255),
geo_ip_142_size INTEGER, iso3166_size INTEGER,
table_dumps_url VARCHAR(2000),
table_dumps_md5 VARCHAR(255),
table_dumps_size INTEGER,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
); );
-- 'maxmind/2014-07-01/GeoIP-139_20140701.zip', '8487b681cc14ea9f603b52db5763a77a', 62399148,
-- 'maxmind/2014-07-01/GeoIP-142_20140701.zip', '2fb4288fa3004ad68a06388f716e4ee5', 2265920,
-- the 1st available release -- the 1st available release
INSERT INTO max_mind_releases VALUES (DEFAULT, DATE '2014-07-01', INSERT INTO max_mind_releases VALUES (DEFAULT, DATE '2014-07-01', FALSE, NULL,
'maxmind/2014-07-01/GeoIP-124_20140701.zip', '93430c4b34b366030054a97c1b595f6f', 1997587, 'maxmind/2014-07-01/GeoIP-124_20140701.zip', '93430c4b34b366030054a97c1b595f6f', 1997587,
'maxmind/2014-07-01/GeoIP-134_20140701.zip', '893c8674656271dac4964d5a56325203', 48198205, 'maxmind/2014-07-01/GeoIP-134_20140701.zip', '893c8674656271dac4964d5a56325203', 48198205,
'maxmind/2014-07-01/GeoIP-139_20140701.zip', '8487b681cc14ea9f603b52db5763a77a', 62399148, 'maxmind/2014-07-01/region_codes.csv', '74c174dc9132a95e56adf4ce32d38909', 76500,
'maxmind/2014-07-01/GeoIP-142_20140701.zip', '2fb4288fa3004ad68a06388f716e4ee5', 2265920, 'maxmind/2014-07-01/iso3166.csv', 'f2c15e4a163468b0b08ebedab1507911', 4282,
DEFAULT, DEFAULT); 'maxmind/2014-07-01/copies.zip', '3a7ddf36b3a8433c19e1b9afcbd2bb77', 178660266,
DEFAULT, DEFAULT);
-- this created_at column will be used by the score_histories import process to chunk work correctly
ALTER TABLE scores ADD COLUMN created_at TIMESTAMP;
UPDATE SCORES SET created_at = score_dt;
ALTER TABLE scores ALTER COLUMN created_at SET DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE scores ALTER COLUMN created_at SET NOT NULL;
DROP TABLE max_mind_isp;
DROP TABLE max_mind_geo;

View File

@ -1,71 +1,99 @@
-- cooking up some better test data for use with findblah -- cooking up some better test data for use with findblah
delete from GeoIPLocations; -- my_audio_latency can have a special value of -1, which means 'unknown'.
insert into GeoIPLocations (locId, countryCode, region, city, postalCode, latitude, longitude, metroCode, areaCode) values CREATE OR REPLACE FUNCTION generate_scores_dataset () RETURNS VOID STRICT VOLATILE AS $$
(17192,'US','TX','Austin','78749',30.2076,-97.8587,635,'512'), BEGIN
(667,'US','TX','Dallas','75207',32.7825,-96.8207,623,'214'),
(30350,'US','TX','Houston','77001',29.7633,-95.3633,618,'713'),
(31423,'US','CO','Denver','80201',39.7392,-104.9847,751,'303'),
(1807,'US','TX','San Antonio','78201',29.4713,-98.5353,641,'210'),
(23565,'US','FL','Miami','33101',25.7743,-80.1937,528,'305'),
(11704,'US','FL','Tampa','33601',27.9475,-82.4584,539,'813'),
(26424,'US','MA','Boston','02101',42.3584,-71.0598,506,'617'),
(5059,'US','ME','Portland','04101',43.6589,-70.2615,500,'207'),
(2739,'US','OR','Portland','97201',45.5073,-122.6932,820,'503'),
(1539,'US','WA','Seattle','98101',47.6103,-122.3341,819,'206'),
(2720,'US','CA','Mountain View','94040',37.3845,-122.0881,807,'650'),
(154078,'US','AR','Mountain View','72560',35.8732,-92.0717,693,'870'),
(3964,'US','CA','Barstow','92311',34.9701,-116.9929,803,'760'),
(14447,'US','OK','Tulsa','74101',36.154,-95.9928,671,'918'),
(162129,'US','TN','Memphis','37501',35.1693,-89.9904,640,'713');
delete from GeoIPBlocks; delete from GeoIPLocations;
insert into GeoIPBlocks (beginIp, endIp, locId) values insert into GeoIPLocations (locId, countryCode, region, city, postalCode, latitude, longitude, metroCode, areaCode) values
(x'00000000'::bigint,x'0FFFFFFF'::bigint,17192), (17192,'US','TX','Austin','78749',30.2076,-97.8587,635,'512'),
(x'10000000'::bigint,x'1FFFFFFF'::bigint,667), (667,'US','TX','Dallas','75207',32.7825,-96.8207,623,'214'),
(x'20000000'::bigint,x'2FFFFFFF'::bigint,30350), (30350,'US','TX','Houston','77001',29.7633,-95.3633,618,'713'),
(x'30000000'::bigint,x'3FFFFFFF'::bigint,31423), (31423,'US','CO','Denver','80201',39.7392,-104.9847,751,'303'),
(x'40000000'::bigint,x'4FFFFFFF'::bigint,1807), (1807,'US','TX','San Antonio','78201',29.4713,-98.5353,641,'210'),
(x'50000000'::bigint,x'5FFFFFFF'::bigint,23565), (23565,'US','FL','Miami','33101',25.7743,-80.1937,528,'305'),
(x'60000000'::bigint,x'6FFFFFFF'::bigint,11704), (11704,'US','FL','Tampa','33601',27.9475,-82.4584,539,'813'),
(x'70000000'::bigint,x'7FFFFFFF'::bigint,26424), (26424,'US','MA','Boston','02101',42.3584,-71.0598,506,'617'),
(x'80000000'::bigint,x'8FFFFFFF'::bigint,5059), (5059,'US','ME','Portland','04101',43.6589,-70.2615,500,'207'),
(x'90000000'::bigint,x'9FFFFFFF'::bigint,2739), (2739,'US','OR','Portland','97201',45.5073,-122.6932,820,'503'),
(x'A0000000'::bigint,x'AFFFFFFF'::bigint,1539), (1539,'US','WA','Seattle','98101',47.6103,-122.3341,819,'206'),
(x'B0000000'::bigint,x'BFFFFFFF'::bigint,2720), (2720,'US','CA','Mountain View','94040',37.3845,-122.0881,807,'650'),
(x'C0000000'::bigint,x'CFFFFFFF'::bigint,154078), (154078,'US','AR','Mountain View','72560',35.8732,-92.0717,693,'870'),
(x'D0000000'::bigint,x'DFFFFFFF'::bigint,3964), (3964,'US','CA','Barstow','92311',34.9701,-116.9929,803,'760'),
(x'E0000000'::bigint,x'EFFFFFFF'::bigint,14447), (14447,'US','OK','Tulsa','74101',36.154,-95.9928,671,'918'),
(x'F0000000'::bigint,x'FFFEFFFF'::bigint,162129); (162129,'US','TN','Memphis','37501',35.1693,-89.9904,640,'713');
-- (x'FFFF0000'::bigint,x'FFFFFFFF'::bigint,bogus)
delete from GeoIPISP; delete from GeoIPBlocks;
insert into GeoIPISP values insert into GeoIPBlocks (beginIp, endIp, locId) values
(x'00000000'::bigint,x'0FFFFFFF'::bigint,'Intergalactic Boogie'), (x'00000000'::bigint,x'0FFFFFFF'::bigint,17192),
(x'10000000'::bigint,x'1FFFFFFF'::bigint,'Powerful Pipes'), (x'10000000'::bigint,x'1FFFFFFF'::bigint,667),
(x'20000000'::bigint,x'2FFFFFFF'::bigint,'Powerful Pipes'), (x'20000000'::bigint,x'2FFFFFFF'::bigint,30350),
(x'30000000'::bigint,x'3FFFFFFF'::bigint,'Intergalactic Boogie'), (x'30000000'::bigint,x'3FFFFFFF'::bigint,31423),
(x'40000000'::bigint,x'4FFFFFFF'::bigint,'Tangled Webs'), (x'40000000'::bigint,x'4FFFFFFF'::bigint,1807),
(x'50000000'::bigint,x'5FFFFFFF'::bigint,'Tangled Webs'), (x'50000000'::bigint,x'5FFFFFFF'::bigint,23565),
(x'60000000'::bigint,x'6FFFFFFF'::bigint,'Powerful Pipes'), (x'60000000'::bigint,x'6FFFFFFF'::bigint,11704),
(x'70000000'::bigint,x'7FFFFFFF'::bigint,'Intergalactic Boogie'), (x'70000000'::bigint,x'7FFFFFFF'::bigint,26424),
(x'80000000'::bigint,x'8FFFFFFF'::bigint,'Greasy Lightning'), (x'80000000'::bigint,x'8FFFFFFF'::bigint,5059),
(x'90000000'::bigint,x'9FFFFFFF'::bigint,'Powerful Pipes'), (x'90000000'::bigint,x'9FFFFFFF'::bigint,2739),
(x'A0000000'::bigint,x'AFFFFFFF'::bigint,'Intergalactic Boogie'), (x'A0000000'::bigint,x'AFFFFFFF'::bigint,1539),
(x'B0000000'::bigint,x'BFFFFFFF'::bigint,'Tangled Webs'), (x'B0000000'::bigint,x'BFFFFFFF'::bigint,2720),
(x'C0000000'::bigint,x'CFFFFFFF'::bigint,'Greasy Lightning'), (x'C0000000'::bigint,x'CFFFFFFF'::bigint,154078),
(x'D0000000'::bigint,x'DFFFFFFF'::bigint,'Tangled Webs'), (x'D0000000'::bigint,x'DFFFFFFF'::bigint,3964),
(x'E0000000'::bigint,x'EFFFFFFF'::bigint,'Intergalactic Boogie'), (x'E0000000'::bigint,x'EFFFFFFF'::bigint,14447),
(x'F0000000'::bigint,x'FFFEFFFF'::bigint,'Powerful Pipes'); (x'F0000000'::bigint,x'FFFEFFFF'::bigint,162129);
-- (x'FFFF0000'::bigint,x'FFFFFFFF'::bigint,'bogus') -- (x'FFFF0000'::bigint,x'FFFFFFFF'::bigint,bogus)
DELETE FROM jamcompany; delete from GeoIPISP;
ALTER SEQUENCE jamcompany_coid_seq RESTART WITH 1; insert into GeoIPISP values
INSERT INTO jamcompany (company) SELECT DISTINCT company FROM geoipisp ORDER BY company; (x'00000000'::bigint,x'0FFFFFFF'::bigint,'Intergalactic Boogie'),
(x'10000000'::bigint,x'1FFFFFFF'::bigint,'Powerful Pipes'),
(x'20000000'::bigint,x'2FFFFFFF'::bigint,'Powerful Pipes'),
(x'30000000'::bigint,x'3FFFFFFF'::bigint,'Intergalactic Boogie'),
(x'40000000'::bigint,x'4FFFFFFF'::bigint,'Tangled Webs'),
(x'50000000'::bigint,x'5FFFFFFF'::bigint,'Tangled Webs'),
(x'60000000'::bigint,x'6FFFFFFF'::bigint,'Powerful Pipes'),
(x'70000000'::bigint,x'7FFFFFFF'::bigint,'Intergalactic Boogie'),
(x'80000000'::bigint,x'8FFFFFFF'::bigint,'Greasy Lightning'),
(x'90000000'::bigint,x'9FFFFFFF'::bigint,'Powerful Pipes'),
(x'A0000000'::bigint,x'AFFFFFFF'::bigint,'Intergalactic Boogie'),
(x'B0000000'::bigint,x'BFFFFFFF'::bigint,'Tangled Webs'),
(x'C0000000'::bigint,x'CFFFFFFF'::bigint,'Greasy Lightning'),
(x'D0000000'::bigint,x'DFFFFFFF'::bigint,'Tangled Webs'),
(x'E0000000'::bigint,x'EFFFFFFF'::bigint,'Intergalactic Boogie'),
(x'F0000000'::bigint,x'FFFEFFFF'::bigint,'Powerful Pipes');
-- (x'FFFF0000'::bigint,x'FFFFFFFF'::bigint,'bogus')
DELETE FROM jamisp; DELETE FROM jamcompany;
INSERT INTO jamisp (beginip, endip, coid) SELECT x.beginip, x.endip, y.coid FROM geoipisp x, jamcompany y WHERE x.company = y.company; ALTER SEQUENCE jamcompany_coid_seq RESTART WITH 1;
INSERT INTO jamcompany (company) SELECT DISTINCT company FROM geoipisp ORDER BY company;
UPDATE geoiplocations SET geog = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)::geography; DELETE FROM jamisp;
UPDATE geoipblocks SET geom = ST_MakeEnvelope(beginip, -1, endip, 1); INSERT INTO jamisp (beginip, endip, coid) SELECT x.beginip, x.endip, y.coid FROM geoipisp x, jamcompany y WHERE x.company = y.company;
UPDATE jamisp SET geom = ST_MakeEnvelope(beginip, -1, endip, 1);
UPDATE geoiplocations SET geog = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)::geography;
UPDATE geoipblocks SET geom = ST_MakeEnvelope(beginip, -1, endip, 1);
UPDATE jamisp SET geom = ST_MakeEnvelope(beginip, -1, endip, 1);
IF EXISTS(
SELECT *
FROM information_schema.tables
WHERE
table_schema = 'public' AND
table_name = 'cities') THEN
DELETE FROM cities;
INSERT INTO cities (city, region, countrycode) select distinct city, region, countrycode from geoiplocations where length(city) > 0 and length(countrycode) > 0;
DELETE FROM regions;
INSERT INTO regions (region, countrycode) select distinct region, countrycode from cities;
DELETE FROM countries;
INSERT INTO countries (countrycode) select distinct countrycode from regions;
END IF;
RETURN;
END;
$$ LANGUAGE plpgsql;
SELECT generate_scores_dataset();

View File

@ -1,2 +1,3 @@
--color --color
--format progress --format progress
--profile

View File

@ -54,7 +54,7 @@ group :test do
gem 'factory_girl', '4.1.0' gem 'factory_girl', '4.1.0'
gem "rspec", "2.11" gem "rspec", "2.11"
gem 'spork', '0.9.0' gem 'spork', '0.9.0'
gem 'database_cleaner', '0.7.0' gem 'database_cleaner', '1.3.0'
gem 'faker', '1.3.0' gem 'faker', '1.3.0'
gem 'resque_spec' #, :path => "/home/jam/src/resque_spec/" gem 'resque_spec' #, :path => "/home/jam/src/resque_spec/"
gem 'timecop' gem 'timecop'

View File

@ -7,3 +7,4 @@ test:
password: postgres password: postgres
timeout: 2000 timeout: 2000
encoding: unicode encoding: unicode
min_messages: warning

View File

@ -19,6 +19,7 @@ require 'cgi'
require 'resque_mailer' require 'resque_mailer'
require 'rest-client' require 'rest-client'
require 'zip' require 'zip'
require 'csv'
require "jam_ruby/constants/limits" require "jam_ruby/constants/limits"
require "jam_ruby/constants/notification_types" require "jam_ruby/constants/notification_types"
@ -67,13 +68,14 @@ require "jam_ruby/app/uploaders/mix_uploader"
require "jam_ruby/app/uploaders/music_notation_uploader" require "jam_ruby/app/uploaders/music_notation_uploader"
require "jam_ruby/app/uploaders/max_mind_release_uploader" require "jam_ruby/app/uploaders/max_mind_release_uploader"
require "jam_ruby/lib/desk_multipass" require "jam_ruby/lib/desk_multipass"
require "jam_ruby/lib/ip"
require "jam_ruby/amqp/amqp_connection_manager" require "jam_ruby/amqp/amqp_connection_manager"
require "jam_ruby/database" require "jam_ruby/database"
require "jam_ruby/message_factory" require "jam_ruby/message_factory"
require "jam_ruby/models/feedback" require "jam_ruby/models/feedback"
require "jam_ruby/models/feedback_observer" require "jam_ruby/models/feedback_observer"
require "jam_ruby/models/max_mind_geo" #require "jam_ruby/models/max_mind_geo"
require "jam_ruby/models/max_mind_isp" #require "jam_ruby/models/max_mind_isp"
require "jam_ruby/models/max_mind_release" require "jam_ruby/models/max_mind_release"
require "jam_ruby/models/band_genre" require "jam_ruby/models/band_genre"
require "jam_ruby/models/genre" require "jam_ruby/models/genre"

View File

@ -12,7 +12,7 @@ class MaxMindReleaseUploader < CarrierWave::Uploader::Base
# Add a white list of extensions which are allowed to be uploaded. # Add a white list of extensions which are allowed to be uploaded.
def extension_white_list def extension_white_list
%w(zip) %w(zip csv)
end end
def store_dir def store_dir
@ -22,19 +22,21 @@ class MaxMindReleaseUploader < CarrierWave::Uploader::Base
# important; this code assumes that the mounted_as ends in _url, and the corresponding _md5 field has the same prefix # important; this code assumes that the mounted_as ends in _url, and the corresponding _md5 field has the same prefix
# this is true for max_mind_release, but not necessarily other models; so careful copy/pasting # this is true for max_mind_release, but not necessarily other models; so careful copy/pasting
def update_extras(file) def update_extras(file)
puts file.inspect
mounted = mounted_as.to_s mounted = mounted_as.to_s
md5_field = mounted[0, mounted.rindex('_url')] + '_md5' md5_field = mounted[0, mounted.rindex('_url')] + '_md5'
size_field = mounted[0, mounted.rindex('_url')] + '_size' size_field = mounted[0, mounted.rindex('_url')] + '_size'
puts "size_field #{size_field}, file.size #{file.size}"
model[size_field.to_sym] = file.size model[size_field.to_sym] = file.size
model[md5_field.to_sym] = ::Digest::MD5.file(file).hexdigest model[md5_field.to_sym] = ::Digest::MD5.file(file).hexdigest
end end
def filename def filename
File.join(model.store_dir, mounted_as.to_s + '.zip') if mounted_as.to_s == 'region_codes_url' || mounted_as.to_s == 'iso3166_url'
ext = '.csv'
else
ext = '.zip'
end
File.join(model.store_dir, mounted_as.to_s + ext)
end end
end end

View File

@ -71,7 +71,7 @@ module JamRuby
#puts("============= GeoIpBlocks.lookup returns #{block.inspect} for #{addr} =============") #puts("============= GeoIpBlocks.lookup returns #{block.inspect} for #{addr} =============")
if block.nil? then locid = 0 else locid = block.locid end if block.nil? then locid = 0 else locid = block.locid end
location = GeoIpLocations.lookup(locid) location = GeoIpLocations.find_by_locid(locid)
if location.nil? if location.nil?
# todo what's a better default location? # todo what's a better default location?
locidispid = 0 locidispid = 0
@ -206,7 +206,7 @@ SQL
#puts("============= GeoIpBlocks.lookup returns #{block.inspect} for #{addr} =============") #puts("============= GeoIpBlocks.lookup returns #{block.inspect} for #{addr} =============")
if block.nil? then locid = 0 else locid = block.locid end if block.nil? then locid = 0 else locid = block.locid end
location = GeoIpLocations.lookup(locid) location = GeoIpLocations.find_by_locid(locid)
if location.nil? if location.nil?
# todo what's a better default location? # todo what's a better default location?
locidispid = 0 locidispid = 0

View File

@ -1,7 +1,23 @@
module JamRuby module JamRuby
def strip_quotes str
return nil if str.nil?
if str.start_with? '"'
str = str[1..-1]
end
if str.end_with? '"'
str = str.chop
end
return str
end
# creates messages (implementation: protocol buffer) objects cleanly # creates messages (implementation: protocol buffer) objects cleanly
class Database class Database
@@log = Logging.logger[Database]
#def self.db_timezone #def self.db_timezone
# @@db_timezone ||= TZInfo::Timezone.get(fetch_db_timezone) # @@db_timezone ||= TZInfo::Timezone.get(fetch_db_timezone)
@ -17,5 +33,26 @@ module JamRuby
result.clear result.clear
tz tz
end end
def self.copy(table_name, file)
@@log.debug("issuing COPY to #{table_name} from #{file}")
raw = GeoIpBlocks.connection.raw_connection
result = raw.copy_data "COPY #{table_name} FROM STDIN" do
File.open(file, 'r').each do |line|
raw.put_copy_data line
end
end
count = GeoIpBlocks.connection.select_value("select count(*) from #{table_name}").to_i
ActiveRecord::Base.logger.debug "loaded #{count} records into #{table_name}"
end
def self.copy_table(table_name)
copied_name = "#{table_name}_copied"
GeoIpBlocks.connection.execute "CREATE TABLE #{copied_name} (LIKE #{table_name} INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING COMMENTS INCLUDING STORAGE)"
copied_name
end
end end
end end

View File

@ -0,0 +1,7 @@
module JamRuby
def ip_address_to_int(ip)
ip.split('.').inject(0) { |total, value| (total << 8) + value.to_i }
end
end

View File

@ -236,12 +236,12 @@ module JamRuby
if self.city if self.city
query = { :city => self.city } query = { :city => self.city }
query[:region] = self.state unless self.state.blank? query[:region] = self.state unless self.state.blank?
query[:country] = self.country unless self.country.blank? query[:countrycode] = self.country unless self.country.blank?
if geo = MaxMindGeo.where(query).limit(1).first if geo = GeoIpLocations.where(query).limit(1).first
geo.lat = nil if geo.lat = 0 geo.latitude = nil if geo.latitude = 0
geo.lng = nil if geo.lng = 0 geo.longitude = nil if geo.longitude = 0
if geo.lat && geo.lng && (self.lat != geo.lat || self.lng != geo.lng) if geo.latitude && geo.longitude && (self.lat != geo.latitude || self.lng != geo.longitude)
self.lat, self.lng = geo.lat, geo.lng self.lat, self.lng = geo.latitude, geo.longitude
return true return true
end end
end end
@ -268,6 +268,11 @@ module JamRuby
(b_members - s_members).blank? (b_members - s_members).blank?
end end
def self.after_maxmind_import(use_copied = true)
table_suffix = use_copied ? '_copied' : ''
Band.connection.execute("UPDATE bands SET lat = geo.latitude, lng = geo.longitude FROM geoiplocations#{table_suffix} as geo WHERE bands.city = geo.city AND bands.state = geo.region AND bands.country = geo.countrycode")
end
private private
def require_at_least_one_genre def require_at_least_one_genre

View File

@ -183,6 +183,20 @@ module JamRuby
end end
end end
def self.update_locidispids(use_copied = true)
# using addr, we can rebuild locidispid
# this will set a connections's _locidispid = 0 if there are no geoiplocations/blocks that match their IP address, or if there are no JamIsps that match the IP address
# otherwise, locidispid will be updated to the correct new value.
# updates all connections's locidispids
table_suffix = use_copied ? '_copied' : ''
Connection.connection.execute("UPDATE connections SET locidispid = COALESCE((SELECT geolocs.locid as geolocid FROM geoipblocks#{table_suffix} as geoblocks INNER JOIN geoiplocations#{table_suffix} as geolocs ON geoblocks.locid = geolocs.locid WHERE geoblocks.geom && ST_MakePoint(addr, 0) AND addr BETWEEN geoblocks.beginip AND geoblocks.endip LIMIT 1) * 1000000::bigint +(SELECT coid FROM jamisp#{table_suffix} as jisp WHERE geom && ST_MakePoint(addr, 0) AND addr BETWEEN beginip AND endip LIMIT 1), 0) ").check
end
def self.after_maxmind_import
update_locidispids
end
private private
def require_at_least_one_track_when_in_session def require_at_least_one_track_when_in_session

View File

@ -1,28 +1,83 @@
module JamRuby module JamRuby
class Country < ActiveRecord::Base class Country < ActiveRecord::Base
@@log = Logging.logger[Country]
self.table_name = 'countries' self.table_name = 'countries'
def self.get_all() def self.get_all()
self.order('countryname asc').all self.order('countryname asc').all
end end
def self.find_iso3166 def self.import_from_iso3166(options)
gem_dir = Gem::Specification.find_by_name("jam_ruby").gem_dir
File.join(gem_dir, 'lib', 'jam_ruby', 'geodata', 'iso3166.csv') file = options[:file]
use_copy = options[:use_copy] ||= false
start = Time.now
copied_table_name = Database.copy_table(self.table_name)
if use_copy
Database.copy(copied_table_name, file)
else
File.open(file, 'r:ISO-8859-1') do |io|
saved_level = ActiveRecord::Base.logger ? ActiveRecord::Base.logger.level : 0
count = 0
stmt = "INSERT INTO #{copied_table_name} (countrycode, countryname) VALUES"
vals = ''
sep = ''
i = 0
n = 20
csv = ::CSV.new(io, {encoding: 'ISO-8859-1', headers: false})
csv.each do |row|
vals = vals+sep+"(#{ActiveRecord::Base.quote_value(row[0])}, #{ActiveRecord::Base.quote_value(row[1])})"
sep = ','
i += 1
if count == 0 or i >= n then
self.connection.execute stmt+vals
count += i
vals = ''
sep = ''
i = 0
if ActiveRecord::Base.logger and ActiveRecord::Base.logger.level > 1 then
ActiveRecord::Base.logger.debug "... logging inserts into #{copied_table_name} suspended ..."
ActiveRecord::Base.logger.level = 1
end
if ActiveRecord::Base.logger and count%10000 < n then
ActiveRecord::Base.logger.level = saved_level
ActiveRecord::Base.logger.debug "... inserted #{count} into #{copied_table_name} ..."
ActiveRecord::Base.logger.level = 1
end
end
end
if i > 0
self.connection.execute stmt+vals
count += i
end
if ActiveRecord::Base.logger then
ActiveRecord::Base.logger.level = saved_level
ActiveRecord::Base.logger.debug "loaded #{count} records into #{copied_table_name}"
end
end # file
end
elapsed = Time.now - start
@@log.debug("#{copied_table_name} import took #{elapsed} seconds")
end end
def self.import_from_iso3166(file = find_iso3166) def self.after_maxmind_import
self.delete_all self.connection.execute("DROP TABLE #{self.table_name}").check
File.open(file, 'r:ISO-8859-1') do |io| self.connection.execute("ALTER TABLE #{self.table_name}_copied RENAME TO #{self.table_name}").check
csv = ::CSV.new(io, {encoding: 'ISO-8859-1', headers: false})
csv.each do |row|
cc = self.new
cc.countrycode = row[0]
cc.countryname = row[1]
cc.save
end
end # file
end end
end end
end end

View File

@ -1,8 +1,17 @@
module JamRuby module JamRuby
class GeoIpBlocks < ActiveRecord::Base class GeoIpBlocks < ActiveRecord::Base
# index names created on the copied table used during import.
# they do not exist except during import
COPIED_GEOIPBLOCKS_INDEX_NAME = 'geoipblocks_copied_geom_gix'
GEOIPBLOCKS_INDEX_NAME = "geoipblocks_geom_gix"
@@log = Logging.logger[GeoIpBlocks]
self.table_name = 'geoipblocks' self.table_name = 'geoipblocks'
belongs_to :location, class_name: 'JamRuby::GeoIpLocations', inverse_of: 'blocks', foreign_key: 'locid'
def self.lookup(ipnum) def self.lookup(ipnum)
self.where('geom && ST_MakePoint(?, 0) AND ? BETWEEN beginip AND endip', ipnum, ipnum) self.where('geom && ST_MakePoint(?, 0) AND ? BETWEEN beginip AND endip', ipnum, ipnum)
.limit(1) .limit(1)
@ -14,14 +23,29 @@ module JamRuby
c.exec_params("insert into #{self.table_name} (beginip, endip, locid, geom) values($1::bigint, $2::bigint, $3, ST_MakeEnvelope($1::bigint, -1, $2::bigint, 1))", [beginip, endip, locid]) c.exec_params("insert into #{self.table_name} (beginip, endip, locid, geom) values($1::bigint, $2::bigint, $3, ST_MakeEnvelope($1::bigint, -1, $2::bigint, 1))", [beginip, endip, locid])
end end
def self.import_from_max_mind(file) def self.ip_lookup(ip_addy)
addr = ip_address_to_int(ip_addy)
self.where(["beginip <= ? AND ? <= endip", addr, addr])
.limit(1)
.first
end
def self.import_from_max_mind(options)
file = options[:file]
use_copy = options[:use_copy]
# File Geo-134 # File Geo-134
# Format: # Format:
# startIpNum,endIpNum,locId # startIpNum,endIpNum,locId
self.transaction do start = Time.now
self.delete_all
copied_table_name = Database.copy_table(self.table_name)
if use_copy
Database.copy(copied_table_name, file)
else
File.open(file, 'r:ISO-8859-1') do |io| File.open(file, 'r:ISO-8859-1') do |io|
s = io.gets.strip # eat the copyright line. gah, why do they have that in their file?? s = io.gets.strip # eat the copyright line. gah, why do they have that in their file??
unless s.eql? 'Copyright (c) 2011 MaxMind Inc. All Rights Reserved.' unless s.eql? 'Copyright (c) 2011 MaxMind Inc. All Rights Reserved.'
@ -40,7 +64,7 @@ module JamRuby
saved_level = ActiveRecord::Base.logger ? ActiveRecord::Base.logger.level : 0 saved_level = ActiveRecord::Base.logger ? ActiveRecord::Base.logger.level : 0
count = 0 count = 0
stmt = "insert into #{self.table_name} (beginip, endip, locid) values" stmt = "INSERT INTO #{copied_table_name} (beginip, endip, locid) VALUES"
vals = '' vals = ''
sep = '' sep = ''
@ -51,8 +75,8 @@ module JamRuby
csv.each do |row| csv.each do |row|
raise "file does not have expected number of columns (3): #{row.length}" unless row.length == 3 raise "file does not have expected number of columns (3): #{row.length}" unless row.length == 3
beginip = MaxMindIsp.ip_address_to_int(MaxMindIsp.strip_quotes(row[0])) beginip = ip_address_to_int(strip_quotes(row[0]))
endip = MaxMindIsp.ip_address_to_int(MaxMindIsp.strip_quotes(row[1])) endip = ip_address_to_int(strip_quotes(row[1]))
locid = row[2] locid = row[2]
vals = vals+sep+"(#{beginip}, #{endip}, #{locid})" vals = vals+sep+"(#{beginip}, #{endip}, #{locid})"
@ -67,13 +91,13 @@ module JamRuby
i = 0 i = 0
if ActiveRecord::Base.logger and ActiveRecord::Base.logger.level > 1 then if ActiveRecord::Base.logger and ActiveRecord::Base.logger.level > 1 then
ActiveRecord::Base.logger.debug "... logging inserts into #{self.table_name} suspended ..." ActiveRecord::Base.logger.debug "... logging inserts into #{copied_table_name} suspended ..."
ActiveRecord::Base.logger.level = 1 ActiveRecord::Base.logger.level = 1
end end
if ActiveRecord::Base.logger and count%10000 < n then if ActiveRecord::Base.logger and count%10000 < n then
ActiveRecord::Base.logger.level = saved_level ActiveRecord::Base.logger.level = saved_level
ActiveRecord::Base.logger.debug "... inserted #{count} into #{self.table_name} ..." ActiveRecord::Base.logger.debug "... inserted #{count} into #{copied_table_name} ..."
ActiveRecord::Base.logger.level = 1 ActiveRecord::Base.logger.level = 1
end end
end end
@ -86,26 +110,37 @@ module JamRuby
if ActiveRecord::Base.logger then if ActiveRecord::Base.logger then
ActiveRecord::Base.logger.level = saved_level ActiveRecord::Base.logger.level = saved_level
ActiveRecord::Base.logger.debug "loaded #{count} records into #{self.table_name}" ActiveRecord::Base.logger.debug "loaded #{count} records into #{copied_table_name}"
end end
sts = self.connection.execute "ALTER TABLE #{self.table_name} DROP COLUMN geom;"
ActiveRecord::Base.logger.debug "DROP COLUMN geom returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
# sts.check [we don't care]
sts = self.connection.execute "ALTER TABLE #{self.table_name} ADD COLUMN geom geometry(polygon);"
ActiveRecord::Base.logger.debug "ADD COLUMN geom returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "UPDATE #{self.table_name} SET geom = ST_MakeEnvelope(beginip, -1, endip, 1);"
ActiveRecord::Base.logger.debug "SET geom returned sts #{sts.cmd_tuples}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "CREATE INDEX #{self.table_name}_geom_gix ON #{self.table_name} USING GIST (geom);"
ActiveRecord::Base.logger.debug "CREATE INDEX #{self.table_name}_geom_gix returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
end end
end end
sts = self.connection.execute "ALTER TABLE #{copied_table_name} DROP COLUMN geom;"
ActiveRecord::Base.logger.debug "DROP COLUMN geom returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
# sts.check [we don't care]
sts = self.connection.execute "ALTER TABLE #{copied_table_name} ADD COLUMN geom geometry(polygon);"
ActiveRecord::Base.logger.debug "ADD COLUMN geom returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "UPDATE #{copied_table_name} SET geom = ST_MakeEnvelope(beginip, -1, endip, 1);"
ActiveRecord::Base.logger.debug "SET geom returned sts #{sts.cmd_tuples}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "CREATE INDEX #{COPIED_GEOIPBLOCKS_INDEX_NAME} ON #{copied_table_name} USING GIST (geom);"
ActiveRecord::Base.logger.debug "CREATE INDEX #{COPIED_GEOIPBLOCKS_INDEX_NAME} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
elapsed = Time.now - start
@@log.debug("#{copied_table_name} import took #{elapsed} seconds")
end
def self.after_maxmind_import
self.connection.execute("DROP TABLE #{self.table_name}").check
self.connection.execute("ALTER INDEX #{COPIED_GEOIPBLOCKS_INDEX_NAME} RENAME TO #{GEOIPBLOCKS_INDEX_NAME}").check
self.connection.execute("ALTER TABLE #{self.table_name}_copied RENAME TO #{self.table_name}").check
end end
end end
end end

View File

@ -1,21 +1,59 @@
module JamRuby module JamRuby
class GeoIpLocations < ActiveRecord::Base class GeoIpLocations < ActiveRecord::Base
self.table_name = 'geoiplocations' # index names created on the copied table used during import.
CITIES_TABLE = 'cities' # they do not exist except during import
REGIONS_TABLE = 'regions' GEOIPLOCATIONS_INDEX_NAME = 'geoiplocations_geog_gix'
COUNTRIES_TABLE = 'countries' COPIED_GEOIPLOCATIONS_INDEX_NAME = 'geoiplocations_copied_geog_gix'
def self.lookup(locid) PRIMARY_KEY_NAME = 'geoiplocations_pkey'
self.where(locid: locid) COPIED_PRIMARY_KEY_NAME = 'geoiplocations_copied_pkey'
.limit(1)
.first @@log = Logging.logger[GeoIpLocations]
self.table_name = 'geoiplocations'
self.primary_key = 'locid'
has_many :blocks, class_name: 'JamRuby::GeoIpBlocks', inverse_of: 'location', foreign_key: 'locid'
# Returns a hash with location information. Fields are nil if they can't be figured.
# This is a class method because it doesn't need to be in a transaction.
def self.lookup(ip_address)
city = state = country = nil
locid = ispid = 0
unless ip_address.nil? || ip_address !~ /^\d+\.\d+\.\d+\.\d+$/
addr = ip_address_to_int(ip_address)
block = GeoIpBlocks.lookup(addr)
if block
locid = block.locid
location = GeoIpLocations.find_by_locid(locid)
if location
# todo translate countrycode to country, region(code) to region
# MSC: it seems fine to store countrycode; the UI can translate countrycode to country display name. same for region
country = location.countrycode
state = location.region
city = location.city
end
end
isp = JamIsp.lookup(addr)
if isp
ispid = isp.coid
end
end
{city: city, state: state, country: country, addr: addr, locidispid: locid*1000000+ispid}
end end
def self.createx(locid, countrycode, region, city, postalcode, latitude, longitude, metrocode, areacode) def self.createx(locid, countrycode, region, city, postalcode, latitude, longitude, metrocode, areacode)
c = connection.raw_connection c = connection.raw_connection
c.exec_params("insert into #{self.table_name} (locid, countrycode, region, city, postalcode, latitude, longitude, metrocode, areacode, geog) values($1, $2, $3, $4, $5, $6, $7, $8, $9, ST_SetSRID(ST_MakePoint($7, $6), 4326)::geography)", c.exec_params("insert into #{self.table_name} (locid, countrycode, region, city, postalcode, latitude, longitude, metrocode, areacode, geog) values($1, $2, $3, $4, $5, $6, $7, $8, $9, ST_SetSRID(ST_MakePoint($7, $6), 4326)::geography)",
[locid, countrycode, region, city, postalcode, latitude, longitude, metrocode, areacode]) [locid, countrycode, region, city, postalcode, latitude, longitude, metrocode, areacode])
end end
def self.i(s) def self.i(s)
@ -23,14 +61,64 @@ module JamRuby
return s.to_i return s.to_i
end end
def self.import_from_max_mind(file) def self.where_latlng(relation, params, current_user=nil)
# this is only valid to call when relation is about bands
distance = params[:distance].to_i
if distance > 0
latlng = nil
location_city = params[:city]
location_state = params[:state]
location_country = params[:country]
remote_ip = params[:remote_ip]
if location_city and location_state and location_country
geo = self.where(city: location_city, region: location_state, countrycode: location_country).limit(1).first
if geo and geo.latitude and geo.longitude and (geo.latitude != 0 or geo.longitude != 0)
# it isn't reasonable for both to be 0...
latlng = [geo.latitude, geo.longitude]
end
elsif current_user and current_user.locidispid and current_user.locidispid != 0
location = GeoIpLocations.find_by_locid(current_user.locidispid/1000000)
if location and location.latitude and location.longitude and (location.latitude != 0 or location.longitude != 0)
# it isn't reasonable for both to be 0...
latlng = [location.latitude, location.longitude]
end
elsif remote_ip
geo = GeoIpBlocks.ip_lookup(remote_ip)
geo = geo.location if geo
if geo and geo.latitude and geo.longitude and (geo.latitude != 0 or geo.longitude != 0)
# it isn't reasonable for both to be 0...
latlng = [geo.latitude, geo.longitude]
end
end
if latlng
relation = relation.where(['latitude IS NOT NULL AND longitude IS NOT NULL']).within(distance, origin: latlng)
end
end
relation
end
def self.import_from_max_mind(options)
file = options[:file]
use_copy = options[:use_copy]
# File Geo-134 # File Geo-134
# Format: # Format:
# locId,country,region,city,postalCode,latitude,longitude,metroCode,areaCode # locId,country,region,city,postalCode,latitude,longitude,metroCode,areaCode
self.transaction do start = Time.now
self.delete_all
copied_table_name = Database.copy_table(self.table_name)
city_copied_table_name = Database.copy_table(City.table_name)
if use_copy
Database.copy(copied_table_name, file)
else
File.open(file, 'r:ISO-8859-1') do |io| File.open(file, 'r:ISO-8859-1') do |io|
s = io.gets.strip # eat the copyright line. gah, why do they have that in their file?? s = io.gets.strip # eat the copyright line. gah, why do they have that in their file??
unless s.eql? 'Copyright (c) 2012 MaxMind LLC. All Rights Reserved.' unless s.eql? 'Copyright (c) 2012 MaxMind LLC. All Rights Reserved.'
@ -49,7 +137,7 @@ module JamRuby
saved_level = ActiveRecord::Base.logger ? ActiveRecord::Base.logger.level : 0 saved_level = ActiveRecord::Base.logger ? ActiveRecord::Base.logger.level : 0
count = 0 count = 0
stmt = "INSERT INTO #{self.table_name} (locid, countrycode, region, city, postalcode, latitude, longitude, metrocode, areacode) VALUES" stmt = "INSERT INTO #{copied_table_name} (locid, countrycode, region, city, postalcode, latitude, longitude, metrocode, areacode) VALUES"
vals = '' vals = ''
sep = '' sep = ''
@ -70,7 +158,7 @@ module JamRuby
metrocode = row[7] metrocode = row[7]
areacode = row[8] areacode = row[8]
vals = vals+sep+"(#{locid}, '#{countrycode}', '#{region}', #{MaxMindIsp.quote_value(city)}, '#{postalcode}', #{latitude}, #{longitude}, #{i(metrocode)}, '#{areacode}')" vals = vals+sep+"(#{locid}, '#{countrycode}', '#{region}', #{quote_value(city)}, '#{postalcode}', #{latitude}, #{longitude}, #{i(metrocode)}, '#{areacode}')"
sep = ',' sep = ','
i += 1 i += 1
@ -82,13 +170,13 @@ module JamRuby
i = 0 i = 0
if ActiveRecord::Base.logger and ActiveRecord::Base.logger.level > 1 then if ActiveRecord::Base.logger and ActiveRecord::Base.logger.level > 1 then
ActiveRecord::Base.logger.debug "... logging inserts into #{self.table_name} suspended ..." ActiveRecord::Base.logger.debug "... logging inserts into #{copied_table_name} suspended ..."
ActiveRecord::Base.logger.level = 1 ActiveRecord::Base.logger.level = 1
end end
if ActiveRecord::Base.logger and count%10000 < n then if ActiveRecord::Base.logger and count%10000 < n then
ActiveRecord::Base.logger.level = saved_level ActiveRecord::Base.logger.level = saved_level
ActiveRecord::Base.logger.debug "... inserted #{count} into #{self.table_name} ..." ActiveRecord::Base.logger.debug "... inserted #{count} into #{copied_table_name} ..."
ActiveRecord::Base.logger.level = 1 ActiveRecord::Base.logger.level = 1
end end
end end
@ -101,50 +189,50 @@ module JamRuby
if ActiveRecord::Base.logger then if ActiveRecord::Base.logger then
ActiveRecord::Base.logger.level = saved_level ActiveRecord::Base.logger.level = saved_level
ActiveRecord::Base.logger.debug "loaded #{count} records into #{self.table_name}" ActiveRecord::Base.logger.debug "loaded #{count} records into #{copied_table_name}"
end end
sts = self.connection.execute "ALTER TABLE #{self.table_name} DROP COLUMN geog;"
ActiveRecord::Base.logger.debug "DROP COLUMN geog returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
# sts.check [we don't care]
sts = self.connection.execute "ALTER TABLE #{self.table_name} ADD COLUMN geog geography(point, 4326);"
ActiveRecord::Base.logger.debug "ADD COLUMN geog returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "UPDATE #{self.table_name} SET geog = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)::geography;"
ActiveRecord::Base.logger.debug "SET geog returned sts #{sts.cmd_tuples}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "CREATE INDEX #{self.table_name}_geog_gix ON #{self.table_name} USING GIST (geog);"
ActiveRecord::Base.logger.debug "CREATE INDEX #{self.table_name}_geog_gix returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "DELETE FROM #{CITIES_TABLE};"
ActiveRecord::Base.logger.debug "DELETE FROM #{CITIES_TABLE} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "INSERT INTO #{CITIES_TABLE} (city, region, countrycode) SELECT DISTINCT city, region, countrycode FROM #{self.table_name} WHERE length(city) > 0 AND length(countrycode) > 0;"
ActiveRecord::Base.logger.debug "INSERT INTO #{CITIES_TABLE} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "DELETE FROM #{REGIONS_TABLE};"
ActiveRecord::Base.logger.debug "DELETE FROM #{REGIONS_TABLE} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "INSERT INTO #{REGIONS_TABLE} (region, regionname, countrycode) SELECT DISTINCT region, region, countrycode FROM #{CITIES_TABLE};"
ActiveRecord::Base.logger.debug "INSERT INTO #{REGIONS_TABLE} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "DELETE FROM #{COUNTRIES_TABLE};"
ActiveRecord::Base.logger.debug "DELETE FROM #{COUNTRIES_TABLE} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "INSERT INTO #{COUNTRIES_TABLE} (countrycode, countryname) SELECT DISTINCT countrycode, countrycode FROM #{REGIONS_TABLE};"
ActiveRecord::Base.logger.debug "INSERT INTO #{COUNTRIES_TABLE} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
end end
end end
# create primary key index -- this will be renamed later in the import process
GeoIpLocations.connection.execute("CREATE UNIQUE INDEX #{COPIED_PRIMARY_KEY_NAME} ON #{copied_table_name} USING btree (locid)").check
GeoIpLocations.connection.execute("ALTER TABLE #{copied_table_name} ADD CONSTRAINT #{COPIED_PRIMARY_KEY_NAME} PRIMARY KEY USING INDEX #{COPIED_PRIMARY_KEY_NAME}").check
sts = self.connection.execute "ALTER TABLE #{copied_table_name} DROP COLUMN geog;"
ActiveRecord::Base.logger.debug "DROP COLUMN geog returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
# sts.check [we don't care]
sts = self.connection.execute "ALTER TABLE #{copied_table_name} ADD COLUMN geog geography(point, 4326);"
ActiveRecord::Base.logger.debug "ADD COLUMN geog returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "UPDATE #{copied_table_name} SET geog = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)::geography;"
ActiveRecord::Base.logger.debug "SET geog returned sts #{sts.cmd_tuples}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "CREATE INDEX #{COPIED_GEOIPLOCATIONS_INDEX_NAME} ON #{copied_table_name} USING GIST (geog);"
ActiveRecord::Base.logger.debug "CREATE INDEX #{COPIED_GEOIPLOCATIONS_INDEX_NAME} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "INSERT INTO #{city_copied_table_name} (city, region, countrycode) SELECT DISTINCT city, region, countrycode FROM #{copied_table_name} WHERE length(city) > 0 AND length(countrycode) > 0;"
ActiveRecord::Base.logger.debug "INSERT INTO #{city_copied_table_name} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
elapsed = Time.now - start
@@log.debug("#{copied_table_name} import took #{elapsed} seconds")
end
def self.after_maxmind_import
# handle geoiplocations
self.connection.execute("DROP TABLE #{self.table_name}").check
self.connection.execute("ALTER INDEX #{COPIED_PRIMARY_KEY_NAME} RENAME TO #{PRIMARY_KEY_NAME}").check
self.connection.execute("ALTER INDEX #{COPIED_GEOIPLOCATIONS_INDEX_NAME} RENAME TO #{GEOIPLOCATIONS_INDEX_NAME}").check
self.connection.execute("ALTER TABLE #{self.table_name}_copied RENAME TO #{self.table_name}").check
# handle cities
self.connection.execute("DROP TABLE #{City.table_name}").check
self.connection.execute("ALTER TABLE #{City.table_name}_copied RENAME TO #{City.table_name}").check
end end
end end
end end

View File

@ -3,6 +3,29 @@ require 'ipaddr'
module JamRuby module JamRuby
class JamIsp < ActiveRecord::Base class JamIsp < ActiveRecord::Base
# index names created on the copied table used during import.
# they do not exist except during import
GEOIPISP_INDEX_NAME = 'geoipisp_company_ndx'
COPIED_GEOIPISP_INDEX_NAME = 'geoipisp_copied_company_ndx'
JAMCOMPANY_UNIQUE_INDEX = 'jamcompany_company_ndx'
COPIED_JAMCOMPANY_UNIQUE_INDEX = 'jamcompany_copied_company_ndx'
JAMCOMPANY_PRIMARY_KEY_NAME = 'jamcompany_pkey'
COPIED_JAMCOMPANY_PRIMARY_KEY_NAME = 'jamcompany_copied_pkey'
COPIED_JAMCOMPANY_COID_SEQUENCE = 'jamcompany_copied_coid_seq'
JAMCOMPANY_COID_SEQUENCE = 'jamcompany_coid_seq'
JAMISP_GEOM_INDEX_NAME = 'jamisp_geom_gix'
COPIED_JAMISP_GEOM_INDEX_NAME = 'jamisp_copied_geom_gix'
JAMISP_COID_INDEX_NAME = 'jamisp_coid_ndx'
COPIED_JAMISP_COID_INDEX_NAME = 'jamisp_copied_coid_ndx'
@@log = Logging.logger[JamIsp]
self.table_name = 'jamisp' self.table_name = 'jamisp'
COMPANY_TABLE = 'jamcompany' COMPANY_TABLE = 'jamcompany'
GEOIPISP_TABLE = 'geoipisp' GEOIPISP_TABLE = 'geoipisp'
@ -27,7 +50,7 @@ module JamRuby
def self.createx(beginip, endip, coid) def self.createx(beginip, endip, coid)
c = connection.raw_connection c = connection.raw_connection
c.exec_params("insert into #{self.table_name} (beginip, endip, coid, geom) values($1::bigint, $2::bigint, $3, ST_MakeEnvelope($1::bigint, -1, $2::bigint, 1))", c.exec_params("insert into #{self.table_name} (beginip, endip, coid, geom) values($1::bigint, $2::bigint, $3, ST_MakeEnvelope($1::bigint, -1, $2::bigint, 1))",
[beginip, endip, coid]) [beginip, endip, coid])
end end
def self_delete() def self_delete()
@ -38,14 +61,24 @@ module JamRuby
raise "mother trucker" raise "mother trucker"
end end
def self.import_from_max_mind(file) def self.import_from_max_mind(options)
file = options[:file]
use_copy = options[:use_copy]
# File Geo-124 # File Geo-124
# Format: # Format:
# startIpNum,endIpNum,isp # startIpNum,endIpNum,isp
self.transaction do start = Time.now
self.connection.execute "delete from #{GEOIPISP_TABLE}"
copied_table_name = Database.copy_table(GEOIPISP_TABLE)
copied_jamcompany_table_name = Database.copy_table(COMPANY_TABLE)
copied_jamisp_table_name = Database.copy_table(self.table_name)
if use_copy
Database.copy(copied_table_name, file)
else
File.open(file, 'r:ISO-8859-1') do |io| File.open(file, 'r:ISO-8859-1') do |io|
#s = io.gets.strip # eat the copyright line. gah, why do they have that in their file?? #s = io.gets.strip # eat the copyright line. gah, why do they have that in their file??
#unless s.eql? 'Copyright (c) 2012 MaxMind LLC. All Rights Reserved.' #unless s.eql? 'Copyright (c) 2012 MaxMind LLC. All Rights Reserved.'
@ -64,7 +97,7 @@ module JamRuby
saved_level = ActiveRecord::Base.logger ? ActiveRecord::Base.logger.level : 0 saved_level = ActiveRecord::Base.logger ? ActiveRecord::Base.logger.level : 0
count = 0 count = 0
stmt = "insert into #{GEOIPISP_TABLE} (beginip, endip, company) values" stmt = "INSERT INTO #{copied_table_name} (beginip, endip, company) VALUES"
vals = '' vals = ''
sep = '' sep = ''
@ -75,11 +108,11 @@ module JamRuby
csv.each do |row| csv.each do |row|
raise "file does not have expected number of columns (3): #{row.length}" unless row.length == 3 raise "file does not have expected number of columns (3): #{row.length}" unless row.length == 3
beginip = MaxMindIsp.ip_address_to_int(MaxMindIsp.strip_quotes(row[0])) beginip = ip_address_to_int(strip_quotes(row[0]))
endip = MaxMindIsp.ip_address_to_int(MaxMindIsp.strip_quotes(row[1])) endip = ip_address_to_int(strip_quotes(row[1]))
company = row[2] company = row[2]
vals = vals+sep+"(#{beginip}, #{endip}, #{MaxMindIsp.quote_value(company)})" vals = vals+sep+"(#{beginip}, #{endip}, #{quote_value(company)})"
sep = ',' sep = ','
i += 1 i += 1
@ -91,13 +124,13 @@ module JamRuby
i = 0 i = 0
if ActiveRecord::Base.logger and ActiveRecord::Base.logger.level > 1 then if ActiveRecord::Base.logger and ActiveRecord::Base.logger.level > 1 then
ActiveRecord::Base.logger.debug "... logging inserts into #{GEOIPISP_TABLE} suspended ..." ActiveRecord::Base.logger.debug "... logging inserts into #{copied_table_name} suspended ..."
ActiveRecord::Base.logger.level = 1 ActiveRecord::Base.logger.level = 1
end end
if ActiveRecord::Base.logger and count%10000 < n then if ActiveRecord::Base.logger and count%10000 < n then
ActiveRecord::Base.logger.level = saved_level ActiveRecord::Base.logger.level = saved_level
ActiveRecord::Base.logger.debug "... inserted #{count} into #{GEOIPISP_TABLE} ..." ActiveRecord::Base.logger.debug "... inserted #{count} into #{copied_table_name} ..."
ActiveRecord::Base.logger.level = 1 ActiveRecord::Base.logger.level = 1
end end
end end
@ -110,46 +143,76 @@ module JamRuby
if ActiveRecord::Base.logger then if ActiveRecord::Base.logger then
ActiveRecord::Base.logger.level = saved_level ActiveRecord::Base.logger.level = saved_level
ActiveRecord::Base.logger.debug "loaded #{count} records into #{GEOIPISP_TABLE}" ActiveRecord::Base.logger.debug "loaded #{count} records into #{copied_table_name}"
end end
sts = GeoIpLocations.connection.execute "DELETE FROM #{COMPANY_TABLE};"
ActiveRecord::Base.logger.debug "DELETE FROM #{COMPANY_TABLE} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = GeoIpLocations.connection.execute "ALTER SEQUENCE #{COMPANY_TABLE}_coid_seq RESTART WITH 1;"
ActiveRecord::Base.logger.debug "ALTER SEQUENCE #{COMPANY_TABLE}_coid_seq returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = GeoIpLocations.connection.execute "INSERT INTO #{COMPANY_TABLE} (company) SELECT DISTINCT company FROM #{GEOIPISP_TABLE} ORDER BY company;"
ActiveRecord::Base.logger.debug "INSERT INTO #{COMPANY_TABLE} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = GeoIpLocations.connection.execute "DELETE FROM #{self.table_name};"
ActiveRecord::Base.logger.debug "DELETE FROM #{self.table_name} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = GeoIpLocations.connection.execute "INSERT INTO #{self.table_name} (beginip, endip, coid) SELECT x.beginip, x.endip, y.coid FROM #{GEOIPISP_TABLE} x, #{COMPANY_TABLE} y WHERE x.company = y.company;"
ActiveRecord::Base.logger.debug "INSERT INTO #{self.table_name} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = GeoIpLocations.connection.execute "ALTER TABLE #{self.table_name} DROP COLUMN geom;"
ActiveRecord::Base.logger.debug "DROP COLUMN geom returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
#sts.check [we don't care]
sts = GeoIpLocations.connection.execute "ALTER TABLE #{self.table_name} ADD COLUMN geom geometry(polygon);"
ActiveRecord::Base.logger.debug "ADD COLUMN geom returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = GeoIpLocations.connection.execute "UPDATE #{self.table_name} SET geom = ST_MakeEnvelope(beginip, -1, endip, 1);"
ActiveRecord::Base.logger.debug "SET geom returned sts #{sts.cmd_tuples}" if ActiveRecord::Base.logger
sts.check
sts = GeoIpLocations.connection.execute "CREATE INDEX #{self.table_name}_geom_gix ON #{self.table_name} USING GIST (geom);"
ActiveRecord::Base.logger.debug "CREATE INDEX #{self.table_name}_geom_gix returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
end end
end end
# add index to copied geoipisp table
GeoIpLocations.connection.execute("CREATE INDEX #{COPIED_GEOIPISP_INDEX_NAME} ON #{copied_table_name} (company)").check
# add sequence to copied_jamcompany table
GeoIpLocations.connection.execute("ALTER TABLE #{copied_jamcompany_table_name} ALTER COLUMN coid DROP DEFAULT").check
GeoIpLocations.connection.execute("CREATE SEQUENCE #{COPIED_JAMCOMPANY_COID_SEQUENCE} START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1").check
GeoIpLocations.connection.execute("ALTER SEQUENCE #{COPIED_JAMCOMPANY_COID_SEQUENCE} OWNED BY #{copied_jamcompany_table_name}.coid").check
GeoIpLocations.connection.execute("ALTER TABLE ONLY #{copied_jamcompany_table_name} ALTER COLUMN coid SET DEFAULT nextval('#{COPIED_JAMCOMPANY_COID_SEQUENCE}'::regclass)").check
sts = GeoIpLocations.connection.execute("INSERT INTO #{copied_jamcompany_table_name} (company) SELECT DISTINCT company FROM #{copied_table_name} ORDER BY company").check
ActiveRecord::Base.logger.debug "INSERT INTO #{copied_table_name} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
# add unique index to copied jamcompany table
GeoIpLocations.connection.execute("CREATE UNIQUE INDEX #{COPIED_JAMCOMPANY_UNIQUE_INDEX} ON #{copied_jamcompany_table_name} (company)").check
# add primary index to copied jamcompany table
GeoIpLocations.connection.execute("CREATE UNIQUE INDEX #{COPIED_JAMCOMPANY_PRIMARY_KEY_NAME} ON #{copied_jamcompany_table_name} USING btree (coid)").check
GeoIpLocations.connection.execute("ALTER TABLE #{copied_jamcompany_table_name} ADD CONSTRAINT #{COPIED_JAMCOMPANY_PRIMARY_KEY_NAME} PRIMARY KEY USING INDEX #{COPIED_JAMCOMPANY_PRIMARY_KEY_NAME}").check
sts = GeoIpLocations.connection.execute "INSERT INTO #{copied_jamisp_table_name} (beginip, endip, coid) SELECT x.beginip, x.endip, y.coid FROM #{copied_table_name} x, #{copied_jamcompany_table_name} y WHERE x.company = y.company"
ActiveRecord::Base.logger.debug "INSERT INTO #{copied_jamisp_table_name} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = GeoIpLocations.connection.execute "ALTER TABLE #{copied_jamisp_table_name} DROP COLUMN geom"
ActiveRecord::Base.logger.debug "DROP COLUMN geom returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
#sts.check [we don't care]
sts = GeoIpLocations.connection.execute "ALTER TABLE #{copied_jamisp_table_name} ADD COLUMN geom geometry(polygon)"
ActiveRecord::Base.logger.debug "ADD COLUMN geom returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = GeoIpLocations.connection.execute "UPDATE #{copied_jamisp_table_name} SET geom = ST_MakeEnvelope(beginip, -1, endip, 1)"
ActiveRecord::Base.logger.debug "SET geom returned sts #{sts.cmd_tuples}" if ActiveRecord::Base.logger
sts.check
# recreate indexes on jamisp
sts = GeoIpLocations.connection.execute "CREATE INDEX #{COPIED_JAMISP_GEOM_INDEX_NAME} ON #{copied_jamisp_table_name} USING GIST (geom)"
ActiveRecord::Base.logger.debug "CREATE INDEX #{COPIED_JAMISP_GEOM_INDEX_NAME} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
GeoIpLocations.connection.execute("CREATE INDEX #{COPIED_JAMISP_COID_INDEX_NAME} ON #{copied_jamisp_table_name} (coid)").check
elapsed = Time.now - start
@@log.debug("#{copied_jamisp_table_name} import took #{elapsed} seconds")
end
def self.after_maxmind_import
# handle jamisp
self.connection.execute("DROP TABLE #{self.table_name}").check
self.connection.execute("ALTER INDEX #{COPIED_JAMISP_GEOM_INDEX_NAME} RENAME TO #{JAMISP_GEOM_INDEX_NAME}").check
self.connection.execute("ALTER INDEX #{COPIED_JAMISP_COID_INDEX_NAME} RENAME TO #{JAMISP_COID_INDEX_NAME}").check
self.connection.execute("ALTER TABLE #{self.table_name}_copied RENAME TO #{self.table_name}").check
# handle geoipisp
self.connection.execute("DROP TABLE #{GEOIPISP_TABLE}").check
self.connection.execute("ALTER INDEX #{COPIED_GEOIPISP_INDEX_NAME} RENAME TO #{GEOIPISP_INDEX_NAME}").check
self.connection.execute("ALTER TABLE #{GEOIPISP_TABLE}_copied RENAME TO #{GEOIPISP_TABLE}").check
# handle jamcompany
self.connection.execute("DROP TABLE #{COMPANY_TABLE}").check
self.connection.execute("ALTER INDEX #{COPIED_JAMCOMPANY_UNIQUE_INDEX} RENAME TO #{JAMCOMPANY_UNIQUE_INDEX}").check
self.connection.execute("ALTER INDEX #{COPIED_JAMCOMPANY_PRIMARY_KEY_NAME} RENAME TO #{JAMCOMPANY_PRIMARY_KEY_NAME}").check
self.connection.execute("ALTER SEQUENCE #{COPIED_JAMCOMPANY_COID_SEQUENCE} RENAME TO #{JAMCOMPANY_COID_SEQUENCE}").check
self.connection.execute("ALTER TABLE #{COMPANY_TABLE}_copied RENAME TO #{COMPANY_TABLE}").check
end end
end end
end end

View File

@ -52,7 +52,7 @@ module JamRuby
if isp.nil? then ispid = 0 else ispid = isp.coid end if isp.nil? then ispid = 0 else ispid = isp.coid end
block = GeoIpBlocks.lookup(addr) block = GeoIpBlocks.lookup(addr)
if block.nil? then locid = 0 else locid = block.locid end if block.nil? then locid = 0 else locid = block.locid end
location = GeoIpLocations.lookup(locid) location = GeoIpLocations.find_by_locid(locid)
if location.nil? if location.nil?
# todo what's a better default location? # todo what's a better default location?
locidispid = 0 locidispid = 0

View File

@ -5,21 +5,24 @@ module JamRuby
self.table_name = 'max_mind_geo' self.table_name = 'max_mind_geo'
def self.ip_lookup(ip_addy) @@log = Logging.logger[MaxMindGeo]
addr = MaxMindIsp.ip_address_to_int(ip_addy)
self.where(["ip_start <= ? AND ? <= ip_end", addr, addr])
.limit(1)
.first
end
def self.import_from_max_mind(file) def self.import_from_max_mind(options)
file = options[:file]
use_copy = options[:use_copy]
# File Geo-139 # File Geo-139
# Format: # Format:
# startIpNum,endIpNum,country,region,city,postalCode,latitude,longitude,dmaCode,areaCode # startIpNum,endIpNum,country,region,city,postalCode,latitude,longitude,dmaCode,areaCode
MaxMindGeo.transaction do start = Time.now
MaxMindGeo.delete_all
MaxMindGeo.delete_all
if use_copy
Database.copy(MaxMindGeo.table_name, file)
else
File.open(file, 'r:ISO-8859-1') do |io| File.open(file, 'r:ISO-8859-1') do |io|
s = io.gets.strip # eat the headers line s = io.gets.strip # eat the headers line
unless s.eql? 'startIpNum,endIpNum,country,region,city,postalCode,latitude,longitude,dmaCode,areaCode' unless s.eql? 'startIpNum,endIpNum,country,region,city,postalCode,latitude,longitude,dmaCode,areaCode'
@ -42,8 +45,8 @@ module JamRuby
csv.each do |row| csv.each do |row|
raise "file does not have expected number of columns (10): #{row.length}" unless row.length == 10 raise "file does not have expected number of columns (10): #{row.length}" unless row.length == 10
ip_start = MaxMindIsp.ip_address_to_int(MaxMindIsp.strip_quotes(row[0])) ip_start = ip_address_to_int(strip_quotes(row[0]))
ip_end = MaxMindIsp.ip_address_to_int(MaxMindIsp.strip_quotes(row[1])) ip_end = ip_address_to_int(strip_quotes(row[1]))
country = row[2] country = row[2]
region = row[3] region = row[3]
city = row[4] city = row[4]
@ -88,8 +91,14 @@ module JamRuby
end end
end end
end end
# User.find_each { |usr| usr.update_lat_lng } # User.find_each { |usr| usr.update_lat_lng }
# THIS DOESNT ACTUALLY DO ANYTHING BECAUSE IT NEVER SAVES
Band.find_each { |bnd| bnd.update_lat_lng } Band.find_each { |bnd| bnd.update_lat_lng }
elapsed = Time.now - start
@@log.debug("#{MaxMindGeo.table_name} import took #{elapsed} seconds")
end end
def self.where_latlng(relation, params, current_user=nil) def self.where_latlng(relation, params, current_user=nil)
@ -103,13 +112,13 @@ module JamRuby
remote_ip = params[:remote_ip] remote_ip = params[:remote_ip]
if location_city and location_state and location_country if location_city and location_state and location_country
geo = self.where(city: location_city, region: location_state, country: location_country).limit(1).first geo = self.where(city: location_city, region: location_state, countrycode: location_country).limit(1).first
if geo and geo.lat and geo.lng and (geo.lat != 0 or geo.lng != 0) if geo and geo.lat and geo.lng and (geo.lat != 0 or geo.lng != 0)
# it isn't reasonable for both to be 0... # it isn't reasonable for both to be 0...
latlng = [geo.lat, geo.lng] latlng = [geo.lat, geo.lng]
end end
elsif current_user and current_user.locidispid and current_user.locidispid != 0 elsif current_user and current_user.locidispid and current_user.locidispid != 0
location = GeoIpLocations.lookup(current_user.locidispid/1000000) location = GeoIpLocations.find_by_locid(current_user.locidispid/1000000)
if location and location.latitude and location.longitude and (location.latitude != 0 or location.longitude != 0) if location and location.latitude and location.longitude and (location.latitude != 0 or location.longitude != 0)
# it isn't reasonable for both to be 0... # it isn't reasonable for both to be 0...
latlng = [location.latitude, location.longitude] latlng = [location.latitude, location.longitude]

View File

@ -5,14 +5,24 @@ module JamRuby
self.table_name = 'max_mind_isp' self.table_name = 'max_mind_isp'
def self.import_from_max_mind(file) @@log = Logging.logger[MaxMindIsp]
def self.import_from_max_mind(options)
file = options[:file]
use_copy = options[:use_copy]
# File Geo-142 # File Geo-142
# Format: # Format:
# "beginIp","endIp","countryCode","ISP" # "beginIp","endIp","countryCode","ISP"
MaxMindIsp.transaction do # drop indexes on start, then add them back when done
MaxMindIsp.delete_all
start = Time.now
MaxMindIsp.delete_all
if use_copy
Database.copy(MaxMind.table_name, file)
else
File.open(file, 'r:ISO-8859-1') do |io| File.open(file, 'r:ISO-8859-1') do |io|
s = io.gets.strip # eat the copyright line. gah, why do they have that in their file?? s = io.gets.strip # eat the copyright line. gah, why do they have that in their file??
unless s.eql? 'Copyright (c) 2011 MaxMind Inc. All Rights Reserved.' unless s.eql? 'Copyright (c) 2011 MaxMind Inc. All Rights Reserved.'
@ -36,7 +46,7 @@ module JamRuby
vals = '' vals = ''
sep = '' sep = ''
i = 0 i = 0
n = 20 # going from 20 to 40 only changed things a little bit n = 20 # going from 20 to 40 only changed things a little bit, and 512 was slower... and 1024 was even slower (weird)
csv = ::CSV.new(io, {encoding: 'ISO-8859-1', headers: false}) csv = ::CSV.new(io, {encoding: 'ISO-8859-1', headers: false})
csv.each do |row| csv.each do |row|
@ -51,19 +61,19 @@ module JamRuby
sep = ',' sep = ','
i += 1 i += 1
if count == 0 or i >= n then if count == 0 or i >= n
MaxMindIsp.connection.execute stmt+vals MaxMindIsp.connection.execute stmt+vals
count += i count += i
vals = '' vals = ''
sep = '' sep = ''
i = 0 i = 0
if ActiveRecord::Base.logger and ActiveRecord::Base.logger.level > 1 then if ActiveRecord::Base.logger and ActiveRecord::Base.logger.level > 1
ActiveRecord::Base.logger.debug "... logging inserts into #{MaxMindIsp.table_name} suspended ..." ActiveRecord::Base.logger.debug "... logging inserts into #{MaxMindIsp.table_name} suspended ..."
ActiveRecord::Base.logger.level = 1 ActiveRecord::Base.logger.level = 1
end end
if ActiveRecord::Base.logger and count%10000 < n then if ActiveRecord::Base.logger and count%10000 < n
ActiveRecord::Base.logger.level = saved_level ActiveRecord::Base.logger.level = saved_level
ActiveRecord::Base.logger.debug "... inserted #{count} into #{MaxMindIsp.table_name} ..." ActiveRecord::Base.logger.debug "... inserted #{count} into #{MaxMindIsp.table_name} ..."
ActiveRecord::Base.logger.level = 1 ActiveRecord::Base.logger.level = 1
@ -71,24 +81,28 @@ module JamRuby
end end
end end
if i > 0 then if i > 0
MaxMindIsp.connection.execute stmt+vals MaxMindIsp.connection.execute stmt+vals
count += i count += i
end end
if ActiveRecord::Base.logger then if ActiveRecord::Base.logger
ActiveRecord::Base.logger.level = saved_level ActiveRecord::Base.logger.level = saved_level
ActiveRecord::Base.logger.debug "loaded #{count} records into #{MaxMindIsp.table_name}" ActiveRecord::Base.logger.debug "loaded #{count} records into #{MaxMindIsp.table_name}"
end end
end end
end end
elapsed = Time.now - start
@@log.debug("#{MaxMindIsp.table_name} import took #{elapsed} seconds")
end end
# Make an IP address fit in a signed int. Just divide it by 2, as the least significant part # Make an IP address fit in a signed int. Just divide it by 2, as the least significant part
# just can't possibly matter. We can verify this if needed. My guess is the entire bottom octet is # just can't possibly matter. We can verify this if needed. My guess is the entire bottom octet is
# actually irrelevant # actually irrelevant
def self.ip_address_to_int(ip) def self.ip_address_to_int(ip)
ip.split('.').inject(0) {|total,value| (total << 8 ) + value.to_i} ip.split('.').inject(0) { |total, value| (total << 8) + value.to_i }
end end
private private

View File

@ -7,27 +7,84 @@ module JamRuby
mount_uploader :geo_ip_124_url, MaxMindReleaseUploader mount_uploader :geo_ip_124_url, MaxMindReleaseUploader
mount_uploader :geo_ip_134_url, MaxMindReleaseUploader mount_uploader :geo_ip_134_url, MaxMindReleaseUploader
mount_uploader :geo_ip_139_url, MaxMindReleaseUploader #mount_uploader :geo_ip_139_url, MaxMindReleaseUploader
mount_uploader :geo_ip_142_url, MaxMindReleaseUploader #mount_uploader :geo_ip_142_url, MaxMindReleaseUploader
mount_uploader :iso3166_url, MaxMindReleaseUploader
mount_uploader :region_codes_url, MaxMindReleaseUploader
mount_uploader :table_dumps_url, MaxMindReleaseUploader
def store_dir def store_dir
"maxmind/#{released_at}" "maxmind/#{released_at}"
end end
def import # if a dump file is found, use it and specify that COPY should be used
def file_or_dump(file, dump)
# you can only import a maxmind release that has released_at specified if dump
unless released_at {file: dump, use_copy:true}
raise "released_at not set in import" else
{file: file, use_copy:false}
end end
end
def import(force_from_source=false)
@@log.debug("-----------------------------------")
@@log.debug("--------- STARTING IMPORT ---------")
@@log.debug("-----------------------------------")
start = Time.now
geo_ip_124_files, geo_ip_134_files, iso3166, region_codes, table_dump_files = download_assets(force_from_source)
import_to_database(geo_ip_124_files, geo_ip_134_files, iso3166, region_codes, table_dump_files)
@@log.debug("IMPORT TOOK: #{Time.now - start} SECONDS")
@@log.debug("-----------------------------------")
@@log.debug("--------- FINISHED IMPORT ---------")
@@log.debug("-----------------------------------")
end
def import_to_database(geo_ip_124_files, geo_ip_134_files, iso3166, region_codes, table_dump_files = {})
MaxMindRelease.transaction do
#MaxMindIsp.import_from_max_mind(file_or_dump(geo_ip_142_files['GeoIPISP-142.csv'], table_dump_files['max_mind_isp.txt']))
#MaxMindGeo.import_from_max_mind(file_or_dump(geo_ip_139_files['GeoIPCity.csv'], table_dump_files['max_mind_geo.txt']))
GeoIpBlocks.import_from_max_mind(file_or_dump(geo_ip_134_files['GeoIPCity-134-Blocks.csv'], table_dump_files['geoipblocks.txt']))
GeoIpLocations.import_from_max_mind(file_or_dump(geo_ip_134_files['GeoIPCity-134-Location.csv'], table_dump_files['geoiplocations.txt']))
JamIsp.import_from_max_mind(file_or_dump(geo_ip_124_files['GeoIPISP.csv'], table_dump_files['geoipisp.txt']))
Country.import_from_iso3166(file_or_dump(iso3166, table_dump_files['countries.txt']))
Region.import_from_region_codes(file_or_dump(region_codes, table_dump_files['regions.txt']))
# updating all scores to an old data to jump-start scoring
@@log.debug("setting all scores 'score_dt' to one day older than initial time")
Score.connection.execute("UPDATE scores SET score_dt = score_dt - interval '1 day'")
# update all user, band, and connection info that is dependent on maxmind
User.after_maxmind_import
Connection.after_maxmind_import
Band.after_maxmind_import
@@log.debug("rename temporary tables over existing tables")
# replace existing tables with new tables
GeoIpBlocks.after_maxmind_import
GeoIpLocations.after_maxmind_import
JamIsp.after_maxmind_import
Country.after_maxmind_import
Region.after_maxmind_import
self.imported = true
self.imported_at = Time.now
self.save!
end
end
def download_assets(force_from_source)
working_dir = dated_working_dir working_dir = dated_working_dir
@@log.debug("downloading and unzipping geoip-142") #@@log.debug("downloading and unzipping geoip-142")
geo_ip_142_files = download_and_unzip(working_dir, :geo_ip_142_url, self[:geo_ip_142_md5]) #geo_ip_142_files = download_and_unzip(working_dir, :geo_ip_142_url, self[:geo_ip_142_md5])
@@log.debug("downloading and unzipping geoip-139") #@@log.debug("downloading and unzipping geoip-139")
geo_ip_139_files = download_and_unzip(working_dir, :geo_ip_139_url, self[:geo_ip_139_md5]) #geo_ip_139_files = download_and_unzip(working_dir, :geo_ip_139_url, self[:geo_ip_139_md5])
@@log.debug("downloading and unzipping geoip-134") @@log.debug("downloading and unzipping geoip-134")
geo_ip_134_files = download_and_unzip(working_dir, :geo_ip_134_url, self[:geo_ip_134_md5]) geo_ip_134_files = download_and_unzip(working_dir, :geo_ip_134_url, self[:geo_ip_134_md5])
@ -35,15 +92,18 @@ module JamRuby
@@log.debug("downloading and unzipping geoip-124") @@log.debug("downloading and unzipping geoip-124")
geo_ip_124_files = download_and_unzip(working_dir, :geo_ip_124_url, self[:geo_ip_124_md5]) geo_ip_124_files = download_and_unzip(working_dir, :geo_ip_124_url, self[:geo_ip_124_md5])
MaxMindIsp.import_from_max_mind(geo_ip_142_files['GeoIPISP-142.csv']) @@log.debug("downloading region_codes")
MaxMindGeo.import_from_max_mind(geo_ip_139_files['GeoIPCity.csv']) region_codes = download(working_dir, :region_codes_url, self[:region_codes_md5])
GeoIpBlocks.import_from_max_mind(geo_ip_134_files['GeoIPCity-134-Blocks.csv'])
GeoIpLocations.import_from_max_mind(geo_ip_134_files['GeoIPCity-134-Location.csv'])
JamIsp.import_from_max_mind(geo_ip_124_files['GeoIPISP.csv'])
Country.import_from_iso3166
Region.import_from_region_codes
@@log.debug("downloading iso3166")
iso3166 = download(working_dir, :iso3166_url, self[:iso3166_md5])
table_dump_files = {}
if self[:table_dumps_url] && !force_from_source
@@log.debug("downloading table dumps")
table_dump_files = download_and_unzip(working_dir, :table_dumps_url, self[:table_dumps_md5])
end
return geo_ip_124_files, geo_ip_134_files, iso3166, region_codes, table_dump_files
end end
def download_and_unzip(working_dir, field, md5) def download_and_unzip(working_dir, field, md5)

View File

@ -19,8 +19,6 @@ module JamRuby
attr_writer :current_user attr_writer :current_user
SOUND = %w(mono stereo) SOUND = %w(mono stereo)
MAX_PART_FAILURES = 3
MAX_UPLOAD_FAILURES = 10
mount_uploader :url, RecordedTrackUploader mount_uploader :url, RecordedTrackUploader
@ -71,7 +69,7 @@ module JamRuby
end end
def validate_too_many_upload_failures def validate_too_many_upload_failures
if upload_failures >= MAX_UPLOAD_FAILURES if upload_failures >= APP_CONFIG.max_track_upload_failures
errors.add(:upload_failures, ValidationMessages::UPLOAD_FAILURES_EXCEEDED) errors.add(:upload_failures, ValidationMessages::UPLOAD_FAILURES_EXCEEDED)
end end
end end

View File

@ -62,7 +62,7 @@ module JamRuby
if recorded_track.is_part_uploading_was if recorded_track.is_part_uploading_was
#recorded_track.reload # we don't want anything else that the user set to get applied #recorded_track.reload # we don't want anything else that the user set to get applied
recorded_track.increment_part_failures(recorded_track.part_failures_was) recorded_track.increment_part_failures(recorded_track.part_failures_was)
if recorded_track.part_failures >= RecordedTrack::MAX_PART_FAILURES if recorded_track.part_failures >= APP_CONFIG.max_track_part_upload_failures
# save upload id before we abort this bad boy # save upload id before we abort this bad boy
upload_id = recorded_track.upload_id upload_id = recorded_track.upload_id
begin begin
@ -71,7 +71,7 @@ module JamRuby
puts e.inspect puts e.inspect
end end
recorded_track.reset_upload recorded_track.reset_upload
if recorded_track.upload_failures >= RecordedTrack::MAX_UPLOAD_FAILURES if recorded_track.upload_failures >= APP_CONFIG.max_track_upload_failures
# do anything? # do anything?
end end
end end

View File

@ -303,7 +303,7 @@ module JamRuby
.where(:user_id => user.id) .where(:user_id => user.id)
.where(:fully_uploaded => false) .where(:fully_uploaded => false)
.where('recorded_tracks.id > ?', since) .where('recorded_tracks.id > ?', since)
.where("upload_failures <= #{RecordedTrack::MAX_UPLOAD_FAILURES}") .where("upload_failures <= #{APP_CONFIG.max_track_upload_failures}")
.where("duration IS NOT NULL") .where("duration IS NOT NULL")
.where('all_discarded = false') .where('all_discarded = false')
.order('recorded_tracks.id') .order('recorded_tracks.id')

View File

@ -1,29 +1,97 @@
module JamRuby module JamRuby
class Region < ActiveRecord::Base class Region < ActiveRecord::Base
# index names created on the copied table used during import.
# they do not exist except during import
COUNTRY_CODE_INDEX_NAME = 'regions_countrycode_ndx'
COPIED_COUNTRY_CODE_INDEX_NAME = 'regions_copied_countrycode_ndx'
UNIQUE_INDEX_NAME = 'regions_countrycode_region_ndx'
COPIED_UNIQUE_INDEX_NAME = 'regions_copied_countrycode_region_ndx'
@@log = Logging.logger[Region]
self.table_name = 'regions' self.table_name = 'regions'
def self.get_all(country) def self.get_all(country)
self.where(countrycode: country).order('regionname asc').all self.where(countrycode: country).order('regionname asc').all
end end
def self.find_region_codes def self.import_from_region_codes(options)
gem_dir = Gem::Specification.find_by_name("jam_ruby").gem_dir
File.join(gem_dir, 'lib', 'jam_ruby', 'geodata', 'region_codes.csv')
end
def self.import_from_region_codes(file = find_region_codes) file = options[:file]
self.delete_all use_copy = options[:use_copy]
File.open(file, 'r:ISO-8859-1') do |io|
csv = ::CSV.new(io, {encoding: 'ISO-8859-1', headers: false}) start = Time.now
csv.each do |row|
rr = Region.new copied_table_name = Database.copy_table(self.table_name)
rr.countrycode = row[0]
rr.region = row[1] if use_copy
rr.regionname = row[2] Database.copy(copied_table_name, file)
rr.save else
File.open(file, 'r:ISO-8859-1') do |io|
saved_level = ActiveRecord::Base.logger ? ActiveRecord::Base.logger.level : 0
count = 0
stmt = "INSERT INTO #{copied_table_name} (countrycode, region, regionname) VALUES"
vals = ''
sep = ''
i = 0
n = 20
csv = ::CSV.new(io, {encoding: 'ISO-8859-1', headers: false})
csv.each do |row|
vals = vals+sep+"(#{ActiveRecord::Base.quote_value(row[0])}, #{ActiveRecord::Base.quote_value(row[1])}, #{ActiveRecord::Base.quote_value(row[2])})"
sep = ','
i += 1
if count == 0 or i >= n then
self.connection.execute stmt+vals
count += i
vals = ''
sep = ''
i = 0
if ActiveRecord::Base.logger and ActiveRecord::Base.logger.level > 1 then
ActiveRecord::Base.logger.debug "... logging inserts into #{copied_table_name} suspended ..."
ActiveRecord::Base.logger.level = 1
end
if ActiveRecord::Base.logger and count%10000 < n then
ActiveRecord::Base.logger.level = saved_level
ActiveRecord::Base.logger.debug "... inserted #{count} into #{copied_table_name} ..."
ActiveRecord::Base.logger.level = 1
end
end
end
if i > 0
self.connection.execute stmt+vals
count += i
end
if ActiveRecord::Base.logger then
ActiveRecord::Base.logger.level = saved_level
ActiveRecord::Base.logger.debug "loaded #{count} records into #{copied_table_name}"
end
end end
end end
# create indexes -- these will be renamed later in the import process
Region.connection.execute("CREATE INDEX #{COPIED_COUNTRY_CODE_INDEX_NAME} ON #{copied_table_name} (countrycode)").check
Region.connection.execute("CREATE UNIQUE INDEX #{COPIED_UNIQUE_INDEX_NAME} ON #{copied_table_name} (countrycode, region)").check
elapsed = Time.now - start
@@log.debug("#{copied_table_name} import took #{elapsed} seconds")
end
def self.after_maxmind_import
self.connection.execute("DROP TABLE #{self.table_name}").check
self.connection.execute("ALTER INDEX #{COPIED_COUNTRY_CODE_INDEX_NAME} RENAME TO #{COUNTRY_CODE_INDEX_NAME}").check
self.connection.execute("ALTER INDEX #{COPIED_UNIQUE_INDEX_NAME} RENAME TO #{UNIQUE_INDEX_NAME}").check
self.connection.execute("ALTER TABLE #{self.table_name}_copied RENAME TO #{self.table_name}").check
end end
end end
end end

View File

@ -415,7 +415,7 @@ module JamRuby
.where(['bgenres.genre_id = ? AND bands.id IS NOT NULL', genre]) .where(['bgenres.genre_id = ? AND bands.id IS NOT NULL', genre])
end end
rel = MaxMindGeo.where_latlng(rel, params, current_user) rel = GeoIpLocations.where_latlng(rel, params, current_user)
sel_str = 'bands.*' sel_str = 'bands.*'
case ordering = self.order_param(params) case ordering = self.order_param(params)

View File

@ -6,6 +6,11 @@ module JamRuby
#devise: for later: :trackable #devise: for later: :trackable
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
JAM_REASON_REGISTRATION = 'r'
JAM_REASON_NETWORK_TEST = 'n'
JAM_REASON_FTUE = 'f'
JAM_REASON_JOIN = 'j'
JAM_REASON_IMPORT = 'i'
devise :database_authenticatable, :recoverable, :rememberable devise :database_authenticatable, :recoverable, :rememberable
@ -130,6 +135,7 @@ module JamRuby
validates :show_whats_next, :inclusion => {:in => [nil, true, false]} validates :show_whats_next, :inclusion => {:in => [nil, true, false]}
validates :mods, json: true validates :mods, json: true
validates_numericality_of :last_jam_audio_latency, greater_than:0, :allow_nil => true validates_numericality_of :last_jam_audio_latency, greater_than:0, :allow_nil => true
validates :last_jam_updated_reason, :inclusion => {:in => [nil, JAM_REASON_REGISTRATION, JAM_REASON_NETWORK_TEST, JAM_REASON_FTUE, JAM_REASON_JOIN, JAM_REASON_IMPORT] }
# custom validators # custom validators
validate :validate_musician_instruments validate :validate_musician_instruments
@ -218,6 +224,7 @@ module JamRuby
loc = self.city.blank? ? '' : self.city loc = self.city.blank? ? '' : self.city
loc = loc.blank? ? self.state : "#{loc}, #{self.state}" unless self.state.blank? loc = loc.blank? ? self.state : "#{loc}, #{self.state}" unless self.state.blank?
#loc = loc.blank? ? self.country : "#{loc}, #{self.country}" unless self.country.blank? #loc = loc.blank? ? self.country : "#{loc}, #{self.country}" unless self.country.blank?
# XXX WHY IS COUNTRY COMMENTED OUT?
loc loc
end end
@ -808,7 +815,7 @@ module JamRuby
if musician if musician
user.last_jam_addr = location[:addr] user.last_jam_addr = location[:addr]
user.last_jam_locidispid = location[:locidispid] user.last_jam_locidispid = location[:locidispid]
user.last_jam_updated_reason = 'r' user.last_jam_updated_reason = JAM_REASON_REGISTRATION
user.last_jam_updated_at = Time.now user.last_jam_updated_at = Time.now
end end
@ -971,6 +978,15 @@ module JamRuby
self.save self.save
end end
def update_last_jam(remote_ip, reason)
location = GeoIpLocations.lookup(remote_ip)
self.last_jam_addr = location[:addr]
self.last_jam_locidispid = location[:locidispid]
self.last_jam_updated_reason = reason
self.last_jam_updated_at = Time.now
save!
end
def escape_filename(path) def escape_filename(path)
dir = File.dirname(path) dir = File.dirname(path)
file = File.basename(path) file = File.basename(path)
@ -1126,6 +1142,24 @@ module JamRuby
!self.city.blank? && (!self.state.blank? || !self.country.blank?) !self.city.blank? && (!self.state.blank? || !self.country.blank?)
end end
def self.update_locidispids(use_copied=true)
# using last_jam_addr, we can rebuild
# * last_jam_locidispid
# * last_jam_updated_reason
# * last_jam_updated_at
# this will set a user's last_jam_locidispid = NULL if there are no geoiplocations/blocks that match their IP address, or if there are no JamIsps that match the IP address
# otherwise, last_jam_locidispid will be updated to the correct new value.
# updates all user's locidispids
table_suffix = use_copied ? '_copied' : ''
User.connection.execute("UPDATE users SET last_jam_locidispid = (SELECT geolocs.locid as geolocid FROM geoipblocks#{table_suffix} as geoblocks INNER JOIN geoiplocations#{table_suffix} AS geolocs ON geoblocks.locid = geolocs.locid WHERE geoblocks.geom && ST_MakePoint(users.last_jam_addr, 0) AND users.last_jam_addr BETWEEN geoblocks.beginip AND geoblocks.endip LIMIT 1) * 1000000::bigint +(SELECT coid FROM jamisp#{table_suffix} as jisp WHERE geom && ST_MakePoint(users.last_jam_addr, 0) AND users.last_jam_addr BETWEEN beginip AND endip LIMIT 1), last_jam_updated_at = NOW(), last_jam_updated_reason='i' ").check
end
def self.after_maxmind_import
update_locidispids
end
# def check_lat_lng # def check_lat_lng
# if (city_changed? || state_changed? || country_changed?) && !lat_changed? && !lng_changed? # if (city_changed? || state_changed? || country_changed?) && !lat_changed? && !lng_changed?
# update_lat_lng # update_lat_lng

View File

@ -245,15 +245,6 @@ FactoryGirl.define do
factory :crash_dump, :class => JamRuby::CrashDump do factory :crash_dump, :class => JamRuby::CrashDump do
end end
factory :geocoder, :class => JamRuby::MaxMindGeo do
country 'US'
sequence(:region) { |n| ['NC', 'CA'][(n-1).modulo(2)] }
sequence(:city) { |n| ['Apex', 'San Francisco'][(n-1).modulo(2)] }
sequence(:ip_start) { |n| [MaxMindIsp.ip_address_to_int('1.1.0.0'), MaxMindIsp.ip_address_to_int('1.1.255.255')][(n-1).modulo(2)] }
sequence(:ip_end) { |n| [MaxMindIsp.ip_address_to_int('1.2.0.0'), MaxMindIsp.ip_address_to_int('1.2.255.255')][(n-1).modulo(2)] }
sequence(:lat) { |n| [35.73265, 37.7742075][(n-1).modulo(2)] }
sequence(:lng) { |n| [-78.85029, -122.4155311][(n-1).modulo(2)] }
end
factory :promo_buzz, :class => JamRuby::PromoBuzz do factory :promo_buzz, :class => JamRuby::PromoBuzz do
text_short Faker::Lorem.characters(10) text_short Faker::Lorem.characters(10)

View File

@ -3,8 +3,6 @@ require 'spec_helper'
describe 'Band search' do describe 'Band search' do
before(:each) do before(:each) do
@geocode1 = FactoryGirl.create(:geocoder)
@geocode2 = FactoryGirl.create(:geocoder)
@bands = [] @bands = []
@bands << @band1 = FactoryGirl.create(:band) @bands << @band1 = FactoryGirl.create(:band)
@bands << @band2 = FactoryGirl.create(:band) @bands << @band2 = FactoryGirl.create(:band)

View File

@ -2,14 +2,8 @@ require 'spec_helper'
describe Band do describe Band do
before(:all) do
MaxMindIsp.delete_all
MaxMindGeo.delete_all
end
before do before do
@geocode1 = FactoryGirl.create(:geocoder) #@geocode2 = FactoryGirl.create(:geocoder)
@geocode2 = FactoryGirl.create(:geocoder)
@band = FactoryGirl.create(:band) @band = FactoryGirl.create(:band)
end end

View File

@ -16,8 +16,6 @@ describe User do
} }
before(:each) do before(:each) do
@geocode1 = FactoryGirl.create(:geocoder)
@geocode2 = FactoryGirl.create(:geocoder)
@user = FactoryGirl.create(:user) @user = FactoryGirl.create(:user)
band.touch band.touch

View File

@ -6,6 +6,7 @@ describe Band do
let(:user2) { FactoryGirl.create(:user) } let(:user2) { FactoryGirl.create(:user) }
let(:fan) { FactoryGirl.create(:fan) } let(:fan) { FactoryGirl.create(:fan) }
let(:band) { FactoryGirl.create(:band) } let(:band) { FactoryGirl.create(:band) }
let(:band_in_austin) { FactoryGirl.create(:band, country: 'US', state: 'TX', city: 'Austin')}
let(:new_band) { FactoryGirl.build(:band) } let(:new_band) { FactoryGirl.build(:band) }
let(:band_params) { let(:band_params) {
{ {
@ -87,4 +88,48 @@ describe Band do
band.errors[:name].should == ["can't be blank"] band.errors[:name].should == ["can't be blank"]
end end
end end
describe "after_maxmind_import" do
before(:each) do
create_phony_database
end
after(:all) do
create_phony_database
end
it "updates to non-null after import if matching location is available" do
band_in_austin.lat.should be_nil
band_in_austin.lng.should be_nil
Band.after_maxmind_import(false)
band_in_austin.reload
band_in_austin.lat.should == 30.2076
band_in_austin.lng.should == -97.8587
end
it "updates to non-null after import if matching location is available, with two matching geoip locations" do
band_in_austin.lat.should be_nil
band_in_austin.lng.should be_nil
# change the dallas entry to austin, to make two austin entries
GeoIpLocations.connection.execute("UPDATE geoiplocations SET city = 'Austin', region = 'TX', countrycode ='US' WHERE city = 'Dallas' AND region = 'TX' and countrycode = 'US'").check
Band.after_maxmind_import(false)
band_in_austin.reload
# you don't know which GeoIpLocation it'll be. So we need to check both
[30.2076, 32.7825].include?(band_in_austin.lat).should be_true
[-97.8587, -96.8207].include?(band_in_austin.lng).should be_true
end
it "updates to null if no matching location available" do
band_in_austin.city = 'Blibbity'
band_in_austin.save!
# change the dallas entry to austin, to make two austin entries
GeoIpLocations.connection.execute("UPDATE geoiplocations SET city = 'Austin', region = 'TX', countrycode ='US' WHERE city = 'Dallas' AND region = 'TX' and countrycode = 'US'").check
Band.after_maxmind_import(false)
band_in_austin.reload
band_in_austin.lat.should be_nil
band_in_austin.lng.should be_nil
end
end
end end

View File

@ -71,4 +71,33 @@ describe JamRuby::Connection do
conn.errors[:last_jam_audio_latency].should == ['is not a number'] conn.errors[:last_jam_audio_latency].should == ['is not a number']
end end
end end
describe "update_locidispids" do
before(:each) do
create_phony_database
end
after(:all) do
create_phony_database
end
it "updates locidispid with valid maxmind data" do
conn.locidispid.should == 0 # default in factory girl
Connection.update_locidispids(false)
conn.reload
conn.locidispid.should == 17192 * 1000000 + JamIsp.lookup(conn.addr).coid
end
it "updates locidispid to 0 with no maxmind data" do
# delete the ATX location info, and update. should be 0
conn.locidispid = 5 # make it not zero to start
conn.save!
GeoIpLocations.connection.execute("DELETE from geoiplocations where city = 'Austin'").check
Connection.update_locidispids(false)
conn.reload
conn.locidispid.should == 0
end
end
end end

View File

@ -0,0 +1,46 @@
require 'spec_helper'
describe Country do
include UsesTempFiles
ISO3166_CSV = 'iso3166.csv'
in_directory_with_file(ISO3166_CSV)
let(:iso3166_data) {tiny_maxmind_dataset[:iso3166]}
before(:each) do
content_for_file(to_csv(iso3166_data))
end
describe "import_from_iso3166" do
after(:all) do
# anything that calls after_maxmind_import seems to break transactions (DatabaseCleaner)
create_phony_database
end
it "succeeds" do
Country.import_from_iso3166(file: ISO3166_CSV)
result = Country.connection.execute("SELECT * FROM countries_copied")
result.ntuples.should == 1
row1 = iso3166_data[0]
result[0]['countrycode'].should == row1[ISO3166_COUNTRYCODE_INDEX]
result[0]['countryname'].should == row1[ISO3166_COUNTRYNAME_INDEX]
list_indexes('countries_copied').should == []
# verify we can swap out tables
Country.after_maxmind_import
table_exists?('countries_copied').should be_false
result = Country.connection.execute("SELECT * FROM countries")
result.ntuples.should == 1
list_indexes('countries').should =~ []
end
end
end

View File

@ -132,7 +132,7 @@ describe EmailBatch do
expect(ebatch.fetch_recipients(0,5).count).to eq(0) expect(ebatch.fetch_recipients(0,5).count).to eq(0)
dd = users[0].created_at + ebatch.days_past_for_trigger_index(0).days dd = users[0].created_at + ebatch.days_past_for_trigger_index(0).days
Timecop.travel(dd) Timecop.travel(dd)
expect(ebatch.fetch_recipients(0,5).count).to eq(20) expect(ebatch.fetch_recipients(0,5).count).to eq(users.length)
users.each { |uu| ebatch.make_set(uu, 0) } users.each { |uu| ebatch.make_set(uu, 0) }
expect(ebatch.fetch_recipients(0,5).count).to eq(0) expect(ebatch.fetch_recipients(0,5).count).to eq(0)
users.map &:destroy users.map &:destroy
@ -172,7 +172,7 @@ describe EmailBatch do
end end
it 'loops bunch of users' do it 'loops bunch of users' do
users = [] users = []
20.times { |nn| users << FactoryGirl.create(:user) } 3.times { |nn| users << FactoryGirl.create(:user) }
loops_bunch_of_users(batchp, users) loops_bunch_of_users(batchp, users)
end end
end end
@ -207,7 +207,7 @@ describe EmailBatch do
end end
it 'loops bunch of users' do it 'loops bunch of users' do
users = [] users = []
20.times { |nn| users << FactoryGirl.create(:user, :first_downloaded_client_at => Time.now) } 3.times { |nn| users << FactoryGirl.create(:user, :first_downloaded_client_at => Time.now) }
loops_bunch_of_users(batchp, users) loops_bunch_of_users(batchp, users)
end end
end end
@ -242,7 +242,7 @@ describe EmailBatch do
end end
it 'loops bunch of users' do it 'loops bunch of users' do
users = [] users = []
20.times { |nn| users << FactoryGirl.create(:user, :first_ran_client_at => Time.now) } 3.times { |nn| users << FactoryGirl.create(:user, :first_ran_client_at => Time.now) }
loops_bunch_of_users(batchp, users) loops_bunch_of_users(batchp, users)
end end
end end
@ -277,7 +277,7 @@ describe EmailBatch do
end end
it 'loops bunch of users' do it 'loops bunch of users' do
users = [] users = []
20.times { |nn| users << FactoryGirl.create(:user, :first_certified_gear_at => Time.now) } 3.times { |nn| users << FactoryGirl.create(:user, :first_certified_gear_at => Time.now) }
loops_bunch_of_users(batchp, users) loops_bunch_of_users(batchp, users)
end end
end end
@ -312,7 +312,7 @@ describe EmailBatch do
end end
it 'loops bunch of users' do it 'loops bunch of users' do
users = [] users = []
20.times { |nn| users << FactoryGirl.create(:user, :first_real_music_session_at => Time.now) } 3.times { |nn| users << FactoryGirl.create(:user, :first_real_music_session_at => Time.now) }
loops_bunch_of_users(batchp, users) loops_bunch_of_users(batchp, users)
end end
end end
@ -347,7 +347,7 @@ describe EmailBatch do
end end
it 'loops bunch of users' do it 'loops bunch of users' do
users = [] users = []
20.times { |nn| users << FactoryGirl.create(:user, :first_real_music_session_at => Time.now) } 3.times { |nn| users << FactoryGirl.create(:user, :first_real_music_session_at => Time.now) }
loops_bunch_of_users(batchp, users) loops_bunch_of_users(batchp, users)
end end
end end
@ -381,7 +381,7 @@ describe EmailBatch do
end end
it 'loops bunch of users' do it 'loops bunch of users' do
users = [] users = []
20.times { |nn| users << FactoryGirl.create(:user) } 3.times { |nn| users << FactoryGirl.create(:user) }
loops_bunch_of_users(batchp, users) loops_bunch_of_users(batchp, users)
end end
end end
@ -415,7 +415,7 @@ describe EmailBatch do
end end
it 'loops bunch of users' do it 'loops bunch of users' do
users = [] users = []
20.times { |nn| users << FactoryGirl.create(:user) } 3.times { |nn| users << FactoryGirl.create(:user) }
loops_bunch_of_users(batchp, users) loops_bunch_of_users(batchp, users)
end end
end end
@ -449,7 +449,7 @@ describe EmailBatch do
end end
it 'loops bunch of users' do it 'loops bunch of users' do
users = [] users = []
20.times { |nn| users << FactoryGirl.create(:user) } 3.times { |nn| users << FactoryGirl.create(:user) }
loops_bunch_of_users(batchp, users) loops_bunch_of_users(batchp, users)
end end
end end

View File

@ -2,16 +2,9 @@ require 'spec_helper'
describe GeoIpBlocks do describe GeoIpBlocks do
#before do include UsesTempFiles
#GeoIpBlocks.delete_all
#GeoIpBlocks.createx(0x01020300, 0x010203ff, 1)
#GeoIpBlocks.createx(0x02030400, 0x020304ff, 2)
#end
#after do GEOIPCITY_BLOCKS = 'geo_ip_blocks.csv'
#GeoIpBlocks.delete_all
#GeoIpBlocks.createx(0x00000000, 0xffffffff, 17192)
#end
it "count" do GeoIpBlocks.count.should == 16 end it "count" do GeoIpBlocks.count.should == 16 end
@ -30,4 +23,45 @@ describe GeoIpBlocks do
it "second.locid" do second.locid.should == 667 end it "second.locid" do second.locid.should == 667 end
it "third" do third.should be_nil end it "third" do third.should be_nil end
describe "import_from_max_mind" do
in_directory_with_file(GEOIPCITY_BLOCKS)
let(:geo_ip_city_blocks_data) {tiny_maxmind_dataset[:geo_ip_city_134_blocks]}
before(:each) do
content_for_file("Copyright (c) 2011 MaxMind Inc. All Rights Reserved.\n" +
"startIpNum,endIpNum,locId\n" +
to_csv(geo_ip_city_blocks_data))
end
after(:all) do
# anything that calls after_maxmind_import seems to break transactions (DatabaseCleaner)
create_phony_database
end
it "succeeds" do
GeoIpBlocks.import_from_max_mind(file: GEOIPCITY_BLOCKS)
result = GeoIpBlocks.connection.execute("SELECT * FROM geoipblocks_copied")
result.ntuples.should == 3
row1 = geo_ip_city_blocks_data[0]
result[0]['beginip'].to_i.should == row1[GEOIPBLOCKS_BEGINIP_INDEX]
result[0]['endip'].to_i.should == row1[GEOIPBLOCKS_ENDIP_INDEX]
result[0]['locid'].to_i.should == row1[GEOIPBLOCKS_LOCID_INDEX]
result[0]['geom'].should_not be_nil
list_indexes('geoipblocks_copied').should =~ [GeoIpBlocks::COPIED_GEOIPBLOCKS_INDEX_NAME]
# verify we can swap out tables
GeoIpBlocks.after_maxmind_import
table_exists?('geoipblocks_copied').should be_false
result = GeoIpBlocks.connection.execute("SELECT * FROM geoipblocks")
result.ntuples.should == 3
list_indexes('geoipblocks').should =~ [GeoIpBlocks::GEOIPBLOCKS_INDEX_NAME]
end
end
end end

View File

@ -2,17 +2,20 @@ require 'spec_helper'
describe GeoIpLocations do describe GeoIpLocations do
before do include UsesTempFiles
#GeoIpLocations.delete_all
#GeoIpLocations.createx(17192, 'US', 'TX', 'Austin', '78749', 30.2076, -97.8587, 635, '512') GEOIPCITY_LOCATIONS = 'geo_ip_locations.csv'
#GeoIpLocations.createx(48086, 'MX', '28', 'Matamoros', '', 25.8833, -97.5000, nil, '')
end
it "count" do GeoIpLocations.count.should == 16 end it "count" do GeoIpLocations.count.should == 16 end
let(:first) { GeoIpLocations.lookup(17192) }
let(:second) { GeoIpLocations.lookup(1539) } before(:all) do
let(:third) { GeoIpLocations.lookup(999999) } # bogus create_phony_database
end
let(:first) { GeoIpLocations.find_by_locid(17192) }
let(:second) { GeoIpLocations.find_by_locid(1539) }
let(:third) { GeoIpLocations.find_by_locid(999999) } # bogus
describe "first" do describe "first" do
it "first" do first.should_not be_nil end it "first" do first.should_not be_nil end
@ -35,4 +38,69 @@ describe GeoIpLocations do
end end
it "third" do third.should be_nil end it "third" do third.should be_nil end
describe "import_from_max_mind" do
in_directory_with_file(GEOIPCITY_LOCATIONS)
let(:geo_ip_city_locations_data) {tiny_maxmind_dataset[:geo_ip_city_134_locations]}
before(:each) do
content_for_file("Copyright (c) 2012 MaxMind LLC. All Rights Reserved.\n" +
"locId,country,region,city,postalCode,latitude,longitude,metroCode,areaCode\n" +
to_csv(geo_ip_city_locations_data))
create_phony_database
end
after(:all) do
# anything that calls after_maxmind_import seems to break transactions (DatabaseCleaner)
create_phony_database
end
it "succeeds" do
GeoIpLocations.import_from_max_mind(file: GEOIPCITY_LOCATIONS)
result = GeoIpLocations.connection.execute("SELECT * FROM geoiplocations_copied")
result.ntuples.should == 3
row1 = geo_ip_city_locations_data[0]
result[0]['locid'].to_i.should == row1[GEOIPLOCATIONS_LOCID_INDEX]
result[0]['countrycode'].should == row1[GEOIPLOCATIONS_COUNTRY_INDEX]
result[0]['region'].should == row1[GEOIPLOCATIONS_REGION_INDEX]
result[0]['city'].should == row1[GEOIPLOCATIONS_CITY_INDEX]
result[0]['postalcode'].should == row1[GEOIPLOCATIONS_POSTALCODE_INDEX]
result[0]['latitude'].to_f.should == row1[GEOIPLOCATIONS_LATITUDE_INDEX]
result[0]['longitude'].to_f.should == row1[GEOIPLOCATIONS_LONGITUDE_INDEX]
result[0]['metrocode'].to_i.should == row1[GEOIPLOCATIONS_METROCODE_INDEX]
result[0]['areacode'].to_i.should == row1[GEOIPLOCATIONS_AREACODE_INDEX]
result[0]['geog'].should_not be_nil
list_indexes('geoiplocations_copied').should =~ [GeoIpLocations::COPIED_PRIMARY_KEY_NAME, GeoIpLocations::COPIED_GEOIPLOCATIONS_INDEX_NAME]
# confirm that the cities table also got copied
result = GeoIpLocations.connection.execute('SELECT * FROM cities_copied')
result.ntuples.should == 1
result[0]['city'].should == row1[GEOIPLOCATIONS_CITY_INDEX]
result[0]['region'].should == row1[GEOIPLOCATIONS_REGION_INDEX]
result[0]['countrycode'].should == row1[GEOIPLOCATIONS_COUNTRY_INDEX]
list_indexes('cities_copied').should =~ []
# verify we can swap out tables
GeoIpLocations.after_maxmind_import
table_exists?('geoiplocations_copied').should be_false
result = GeoIpLocations.connection.execute("SELECT * FROM geoiplocations")
result.ntuples.should == 3
list_indexes('geoiplocations').should =~ [GeoIpLocations::PRIMARY_KEY_NAME, GeoIpLocations::GEOIPLOCATIONS_INDEX_NAME]
table_exists?('cities_copied').should be_false
result = GeoIpLocations.connection.execute("SELECT * FROM cities")
result.ntuples.should == 1
list_indexes('cities').should =~ []
end
end
end end

View File

@ -2,20 +2,9 @@ require 'spec_helper'
describe JamIsp do describe JamIsp do
#before do include UsesTempFiles
# JamIsp.delete_all
# JamIsp.createx(0x01020300, 0x010203ff, 1)
# JamIsp.createx(0x02030400, 0x020304ff, 2)
# JamIsp.createx(0x03040500, 0x030405ff, 3)
# JamIsp.createx(0x04050600, 0x040506ff, 4)
# JamIsp.createx(0xc0A80100, 0xc0A801ff, 5)
# JamIsp.createx(0xfffefd00, 0xfffefdff, 6)
#end
#after do GEOIPISP = 'geoip_isp.csv'
# JamIsp.delete_all
# JamIsp.createx(0x00000000, 0xffffffff, 1)
#end
it "count" do JamIsp.count.should == 16 end it "count" do JamIsp.count.should == 16 end
@ -42,4 +31,73 @@ describe JamIsp do
it "second.coid" do second.coid.should == 3 end it "second.coid" do second.coid.should == 3 end
it "third.coid" do third.coid.should == 4 end it "third.coid" do third.coid.should == 4 end
it "seventh" do seventh.should be_nil end it "seventh" do seventh.should be_nil end
describe "import_from_max_mind" do
in_directory_with_file(GEOIPISP)
let(:geo_ip_isp_data) {tiny_maxmind_dataset[:geo_ip_isp]}
before(:each) do
create_phony_database
content_for_file(to_csv(geo_ip_isp_data))
end
after(:all) do
# anything that calls after_maxmind_import seems to break transactions (DatabaseCleaner)
create_phony_database
end
it "succeeded" do
JamIsp.import_from_max_mind(file: GEOIPISP)
# verify geoipisp
result = JamIsp.connection.execute("SELECT * FROM geoipisp_copied")
result.ntuples.should == 1
row1 = geo_ip_isp_data[0]
result[0]['beginip'].to_i.should == row1[GEOIPISP_BEGINIP_INDEX]
result[0]['endip'].to_i.should == row1[GEOIPISP_ENDIP_INDEX]
result[0]['company'].should == row1[GEOIPISP_COMPANY_INDEX]
list_indexes('geoipisp_copied').should =~ [JamIsp::COPIED_GEOIPISP_INDEX_NAME]
# verify jamcompany
result = JamIsp.connection.execute("SELECT * FROM jamcompany_copied")
result.ntuples.should == 1
row1 = geo_ip_isp_data[0]
result[0]['coid'].to_i.should == 1
result[0]['company'].should == row1[GEOIPISP_COMPANY_INDEX]
list_indexes('jamcompany_copied').should =~ [JamIsp::COPIED_JAMCOMPANY_UNIQUE_INDEX, JamIsp::COPIED_JAMCOMPANY_PRIMARY_KEY_NAME]
# verify jamisp
result = JamIsp.connection.execute("SELECT * FROM jamisp_copied")
result.ntuples.should == 1
row1 = geo_ip_isp_data[0]
result[0]['beginip'].to_i.should == row1[GEOIPISP_BEGINIP_INDEX]
result[0]['endip'].to_i.should == row1[GEOIPISP_ENDIP_INDEX]
result[0]['coid'].to_i.should == 1
result[0]['geom'].should_not be_nil
list_indexes('jamisp_copied').should =~ [JamIsp::COPIED_JAMISP_GEOM_INDEX_NAME, JamIsp::COPIED_JAMISP_COID_INDEX_NAME]
# verify we can swap out tables
JamIsp.after_maxmind_import
table_exists?('jamisp_copied').should be_false
result = JamIsp.connection.execute("SELECT * FROM jamisp")
result.ntuples.should == 1
list_indexes('jamisp').should =~ [JamIsp::JAMISP_GEOM_INDEX_NAME, JamIsp::JAMISP_COID_INDEX_NAME]
table_exists?('jamcompany_copied').should be_false
result = JamIsp.connection.execute("SELECT * FROM jamcompany")
result.ntuples.should == 1
list_indexes('jamcompany').should =~ [JamIsp::JAMCOMPANY_UNIQUE_INDEX, JamIsp::JAMCOMPANY_PRIMARY_KEY_NAME]
table_exists?('geoipisp_copied').should be_false
result = JamIsp.connection.execute("SELECT * FROM geoipisp")
result.ntuples.should == 1
list_indexes('geoipisp').should =~ [JamIsp::GEOIPISP_INDEX_NAME]
end
end
end end

View File

@ -1,37 +0,0 @@
require 'spec_helper'
describe MaxMindGeo do
include UsesTempFiles
GEO_CSV='small.csv'
in_directory_with_file(GEO_CSV)
before do
content_for_file('startIpNum,endIpNum,country,region,city,postalCode,latitude,longitude,dmaCode,areaCode
0.116.0.0,0.119.255.255,"AT","","","",47.3333,13.3333,123,123
1.0.0.0,1.0.0.255,"AU","","","",-27.0000,133.0000,,
1.0.1.0,1.0.1.255,"CN","07","Fuzhou","",26.0614,119.3061,,'.encode(Encoding::ISO_8859_1))
MaxMindGeo.import_from_max_mind(GEO_CSV)
end
it { MaxMindGeo.count.should == 3 }
let(:first) { MaxMindGeo.find_by_ip_start(MaxMindIsp.ip_address_to_int('0.116.0.0')) }
let(:second) { MaxMindGeo.find_by_ip_start(MaxMindIsp.ip_address_to_int('1.0.0.0')) }
let(:third) { MaxMindGeo.find_by_ip_start(MaxMindIsp.ip_address_to_int('1.0.1.0')) }
it { first.country.should == 'AT' }
it { first.ip_start.should == MaxMindIsp.ip_address_to_int('0.116.0.0') }
it { first.ip_end.should == MaxMindIsp.ip_address_to_int('0.119.255.255') }
it { second.country.should == 'AU' }
it { second.ip_start.should == MaxMindIsp.ip_address_to_int('1.0.0.0') }
it { second.ip_end.should == MaxMindIsp.ip_address_to_int('1.0.0.255') }
it { third.country.should == 'CN' }
it { third.ip_start.should == MaxMindIsp.ip_address_to_int('1.0.1.0') }
it { third.ip_end.should == MaxMindIsp.ip_address_to_int('1.0.1.255') }
end

View File

@ -1,43 +0,0 @@
require 'spec_helper'
describe MaxMindIsp do
include UsesTempFiles
ISP_CSV='small.csv'
in_directory_with_file(ISP_CSV)
before do
content_for_file('Copyright (c) 2011 MaxMind Inc. All Rights Reserved.
"beginIp","endIp","countryCode","ISP"
"1.0.0.0","1.0.0.255","AU","APNIC Debogon Project"
"1.0.1.0","1.0.1.255","CN","Chinanet Fujian Province Network"
"1.0.4.0","1.0.7.255","AU","Bigred,inc"'.encode(Encoding::ISO_8859_1))
MaxMindIsp.import_from_max_mind(ISP_CSV)
end
let(:first) { MaxMindIsp.find_by_ip_bottom(MaxMindIsp.ip_address_to_int('1.0.0.0')) }
let(:second) { MaxMindIsp.find_by_ip_bottom(MaxMindIsp.ip_address_to_int('1.0.1.0')) }
let(:third) { MaxMindIsp.find_by_ip_bottom(MaxMindIsp.ip_address_to_int('1.0.4.0')) }
it { MaxMindIsp.count.should == 3 }
it { first.country.should == 'AU' }
it { first.ip_bottom.should == MaxMindIsp.ip_address_to_int('1.0.0.0') }
it { first.ip_top.should == MaxMindIsp.ip_address_to_int('1.0.0.255') }
it { first.isp.should == 'APNIC Debogon Project' }
it { second.country.should == 'CN' }
it { second.ip_bottom.should == MaxMindIsp.ip_address_to_int('1.0.1.0') }
it { second.ip_top.should == MaxMindIsp.ip_address_to_int('1.0.1.255') }
it { second.isp.should == 'Chinanet Fujian Province Network' }
it { third.country.should == 'AU' }
it { third.ip_bottom.should == MaxMindIsp.ip_address_to_int('1.0.4.0') }
it { third.ip_top.should == MaxMindIsp.ip_address_to_int('1.0.7.255') }
it { third.isp.should == 'Bigred,inc' }
end

View File

@ -47,25 +47,14 @@ describe MaxMindRelease do
Digest::MD5.file(downloaded_filename ).hexdigest.should == Digest::MD5.file(zipfile).hexdigest Digest::MD5.file(downloaded_filename ).hexdigest.should == Digest::MD5.file(zipfile).hexdigest
end end
#it "uploads to s3 with correct name, and then downloads via signed URL" do describe "import" do
# pending "use" it "succeeds" do
# jam_track = FactoryGirl.create(:jam_track) release.touch
# uploader = JamTrackUploader.new(jam_track, :url) dataset = dataset_to_tmp_files
# uploader.store!(File.open(JKA_NAME)) # uploads file release.import_to_database(dataset[:geo_ip_124_files], dataset[:geo_ip_134_files], dataset[:iso3166], dataset[:region_codes])
# jam_track.save! release.imported.should be_true
# release.imported_at.should_not be_nil
# # verify that the uploader stores the correct path end
# jam_track[:url].should == jam_track.store_dir + '/' + jam_track.filename end
#
# # verify it's on S3
# s3 = S3Manager.new(APP_CONFIG.aws_bucket, APP_CONFIG.aws_access_key_id, APP_CONFIG.aws_secret_access_key)
# s3.exists?(jam_track[:url]).should be_true
# s3.length(jam_track[:url]).should == 'abc'.length
#
# # download it via signed URL, and check contents
# url = jam_track.sign_url
# downloaded_contents = open(url).read
# downloaded_contents.should == 'abc'
#end
end end

View File

@ -126,10 +126,10 @@ describe RecordedTrack do
@recorded_track.upload_start(File.size(upload_file), md5) @recorded_track.upload_start(File.size(upload_file), md5)
@recorded_track.upload_next_part(File.size(upload_file), md5) @recorded_track.upload_next_part(File.size(upload_file), md5)
@recorded_track.errors.any?.should be_false @recorded_track.errors.any?.should be_false
RecordedTrack::MAX_PART_FAILURES.times do |i| APP_CONFIG.max_track_part_upload_failures.times do |i|
@recorded_track.upload_part_complete(@recorded_track.next_part_to_upload, File.size(upload_file)) @recorded_track.upload_part_complete(@recorded_track.next_part_to_upload, File.size(upload_file))
@recorded_track.errors[:next_part_to_upload] == [ValidationMessages::PART_NOT_FOUND_IN_AWS] @recorded_track.errors[:next_part_to_upload] == [ValidationMessages::PART_NOT_FOUND_IN_AWS]
part_failure_rollover = i == RecordedTrack::MAX_PART_FAILURES - 1 part_failure_rollover = i == APP_CONFIG.max_track_part_upload_failures - 1
expected_is_part_uploading = !part_failure_rollover expected_is_part_uploading = !part_failure_rollover
expected_part_failures = part_failure_rollover ? 0 : i + 1 expected_part_failures = part_failure_rollover ? 0 : i + 1
@recorded_track.reload @recorded_track.reload
@ -147,15 +147,17 @@ describe RecordedTrack do
end end
it "enough upload failures fails the upload forever" do it "enough upload failures fails the upload forever" do
APP_CONFIG.stub(:max_track_upload_failures).and_return(1)
APP_CONFIG.stub(:max_track_part_upload_failures).and_return(2)
@recorded_track = RecordedTrack.create_from_track(@track, @recording) @recorded_track = RecordedTrack.create_from_track(@track, @recording)
RecordedTrack::MAX_UPLOAD_FAILURES.times do |j| APP_CONFIG.max_track_upload_failures.times do |j|
@recorded_track.upload_start(File.size(upload_file), md5) @recorded_track.upload_start(File.size(upload_file), md5)
@recorded_track.upload_next_part(File.size(upload_file), md5) @recorded_track.upload_next_part(File.size(upload_file), md5)
@recorded_track.errors.any?.should be_false @recorded_track.errors.any?.should be_false
RecordedTrack::MAX_PART_FAILURES.times do |i| APP_CONFIG.max_track_part_upload_failures.times do |i|
@recorded_track.upload_part_complete(@recorded_track.next_part_to_upload, File.size(upload_file)) @recorded_track.upload_part_complete(@recorded_track.next_part_to_upload, File.size(upload_file))
@recorded_track.errors[:next_part_to_upload] == [ValidationMessages::PART_NOT_FOUND_IN_AWS] @recorded_track.errors[:next_part_to_upload] == [ValidationMessages::PART_NOT_FOUND_IN_AWS]
part_failure_rollover = i == RecordedTrack::MAX_PART_FAILURES - 1 part_failure_rollover = i == APP_CONFIG.max_track_part_upload_failures - 1
expected_is_part_uploading = part_failure_rollover ? false : true expected_is_part_uploading = part_failure_rollover ? false : true
expected_part_failures = part_failure_rollover ? 0 : i + 1 expected_part_failures = part_failure_rollover ? 0 : i + 1
@recorded_track.reload @recorded_track.reload
@ -166,7 +168,7 @@ describe RecordedTrack do
end end
@recorded_track.reload @recorded_track.reload
@recorded_track.upload_failures.should == RecordedTrack::MAX_UPLOAD_FAILURES @recorded_track.upload_failures.should == APP_CONFIG.max_track_upload_failures
@recorded_track.file_offset.should == 0 @recorded_track.file_offset.should == 0
@recorded_track.next_part_to_upload.should == 0 @recorded_track.next_part_to_upload.should == 0
@recorded_track.upload_id.should be_nil @recorded_track.upload_id.should be_nil

View File

@ -0,0 +1,46 @@
require 'spec_helper'
describe Region do
include UsesTempFiles
REGION_CODES_CSV = 'region_codes.csv'
in_directory_with_file(REGION_CODES_CSV)
let(:region_codes_data) {tiny_maxmind_dataset[:region_codes]}
before(:each) do
content_for_file(to_csv(region_codes_data))
end
describe "import_from_region_codes" do
after(:all) do
# anything that calls after_maxmind_import seems to break transactions (DatabaseCleaner)
create_phony_database
end
it "succeeds" do
Region.import_from_region_codes(file: REGION_CODES_CSV)
result = Region.connection.execute("SELECT * FROM regions_copied")
result.ntuples.should == 1
row1 = region_codes_data[0]
result[0]['region'].should == row1[REGIONCODES_REGIONCODE_INDEX]
result[0]['regionname'].should == row1[REGIONCODES_REGIONNAME_INDEX]
result[0]['countrycode'].should == row1[REGIONCODES_COUNTRYCODE_INDEX]
list_indexes('regions_copied').should =~ [Region::COPIED_COUNTRY_CODE_INDEX_NAME, Region::COPIED_UNIQUE_INDEX_NAME]
# verify we can swap out tables
Region.after_maxmind_import
table_exists?('regions_copied').should be_false
result = Region.connection.execute("SELECT * FROM regions")
result.ntuples.should == 1
list_indexes('regions').should =~ [Region::COUNTRY_CODE_INDEX_NAME, Region::UNIQUE_INDEX_NAME]
end
end
end

View File

@ -22,20 +22,20 @@ X If no profile location is provided, and the user creates/joins a music session
describe "with profile location data" do describe "with profile location data" do
it "should have lat/lng values" do it "should have lat/lng values" do
pending 'distance search changes' pending 'distance search changes'
geo = MaxMindGeo.find_by_city(@user.city) geo = GeoIpLocations.find_by_city(@user.city).blocks.first
@user.lat.should == geo.lat @user.lat.should == geo.latitude
@user.lng.should == geo.lng @user.lng.should == geo.longitude
end end
it "should have updated lat/lng values" do it "should have updated lat/lng values" do
pending 'distance search changes' pending 'distance search changes'
@user.update_attributes({ :city => @geocode2.city, @user.update_attributes({ :city => @geocode2.city,
:state => @geocode2.region, :state => @geocode2.region,
:country => @geocode2.country, :country => @geocode2.country,
}) })
geo = MaxMindGeo.find_by_city(@user.city) geo = GeoIpLocations.find_by_city(@user.city).blocks.first
@user.lat.should == geo.lat @user.lat.should == geo.latitude
@user.lng.should == geo.lng @user.lng.should == geo.longitude
end end
end end
@ -48,13 +48,13 @@ X If no profile location is provided, and the user creates/joins a music session
}) })
@user.lat.should == nil @user.lat.should == nil
@user.lng.should == nil @user.lng.should == nil
geo = JamRuby::MaxMindGeo.ip_lookup('1.1.0.0') geo = GeoIpBlocks.ip_lookup('1.1.0.0')
geo.should_not be_nil geo.should_not be_nil
geo = JamRuby::MaxMindGeo.ip_lookup('1.1.0.255') geo = GeoIpBlocks.ip_lookup('1.1.0.255')
geo.should_not be_nil geo.should_not be_nil
@user.update_lat_lng('1.1.0.255') @user.update_lat_lng('1.1.0.255')
@user.lat.should == geo.lat @user.lat.should == geo.latitude
@user.lng.should == geo.lng @user.lng.should == geo.longitude
end end
end end

View File

@ -492,6 +492,64 @@ describe User do
@user.errors[:last_jam_audio_latency].should == ['is not a number'] @user.errors[:last_jam_audio_latency].should == ['is not a number']
end end
end end
describe "update_locidispids" do
before(:each) do
@user.save
create_phony_database
end
after(:all) do
create_phony_database
end
it "remains null if the user's last_jam_addr is null" do
@user.last_jam_addr.should be_nil # make sure the factory still makes a null addr to start
User.update_locidispids(false)
@user.reload
@user.last_jam_addr.should be_nil
end
it "locidispid remains non-null and the same as before, if no maxmind info has changed" do
@user.update_last_jam('1.1.1.1', User::JAM_REASON_REGISTRATION)
initial_locidispid = @user.last_jam_locidispid
initial_locidispid.should_not be_nil
User.update_locidispids(false)
@user.reload
@user.last_jam_locidispid.should == initial_locidispid
@user.last_jam_updated_reason.should == User::JAM_REASON_IMPORT
end
it "locidispid goes to null if geoip info is null" do
@user.update_last_jam('1.1.1.1', User::JAM_REASON_REGISTRATION)
initial_locidispid = @user.last_jam_locidispid
initial_locidispid.should_not be_nil
GeoIpBlocks.delete_all
User.update_locidispids(false)
@user.reload
@user.last_jam_locidispid.should be_nil
@user.last_jam_updated_reason.should == User::JAM_REASON_IMPORT
end
it "locidispid updates to a new value if geoip info changes" do
@user.update_last_jam('1.1.1.1', User::JAM_REASON_REGISTRATION)
initial_locidispid = @user.last_jam_locidispid
initial_locidispid.should_not be_nil
GeoIpBlocks.connection.execute("UPDATE geoipblocks SET locid = 17193::bigint where locid = 17192::bigint").check
GeoIpLocations.connection.execute("UPDATE geoiplocations SET locid = 17193::bigint where locid = 17192::bigint").check
GeoIpLocations.find_by_locid(17193).should_not be_nil
GeoIpBlocks.find_by_locid(17193).should_not be_nil
User.update_locidispids(false)
@user.reload
@user.last_jam_locidispid.should_not == initial_locidispid
@user.last_jam_locidispid.should == 17193 * 1000000 + JamIsp.lookup(@user.last_jam_addr).coid
@user.last_jam_updated_reason.should == User::JAM_REASON_IMPORT
end
end
=begin =begin
describe "update avatar" do describe "update avatar" do

View File

@ -21,12 +21,12 @@ describe "ActiveMusicSessionCleaner" do
c.delete c.delete
end end
# hasn't been 1 minute yet # hasn't been 1 second yet
@cleaner.run @cleaner.run
ActiveMusicSession.all.count.should == 1 ActiveMusicSession.all.count.should == 1
ams = ActiveMusicSession.first
# wait 3 seconds so the updated_at expires ams.updated_at = 3.seconds.ago
sleep 3 ams.save!
@cleaner.run @cleaner.run
ActiveMusicSession.all.count.should == 0 ActiveMusicSession.all.count.should == 0

View File

@ -4,6 +4,7 @@ ENV["RAILS_ENV"] = "test"
require 'simplecov' require 'simplecov'
require 'support/utilities' require 'support/utilities'
require 'support/profile' require 'support/profile'
require 'support/maxmind'
require 'active_record' require 'active_record'
require 'jam_db' require 'jam_db'
require 'spec_db' require 'spec_db'
@ -56,7 +57,7 @@ end
#uncomment the following line to use spork with the debugger #uncomment the following line to use spork with the debugger
#require 'spork/ext/ruby-debug' #require 'spork/ext/ruby-debug'
Spork.prefork do #Spork.prefork do
# Loading more in this block will cause your tests to run faster. However, # Loading more in this block will cause your tests to run faster. However,
# if you change any configuration or code from libraries loaded here, you'll # if you change any configuration or code from libraries loaded here, you'll
# need to restart spork for it take effect. # need to restart spork for it take effect.
@ -83,8 +84,9 @@ Spork.prefork do
config.filter_run_excluding aws: true unless run_tests? :aws config.filter_run_excluding aws: true unless run_tests? :aws
config.before(:suite) do config.before(:suite) do
DatabaseCleaner.strategy = :truncation, {:except => %w[instruments genres icecast_server_groups jamcompany jamisp geoipblocks geoipisp geoiplocations cities regions countries] } DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation, {:except => %w[instruments genres icecast_server_groups jamcompany jamisp geoipblocks geoipisp geoiplocations cities regions countries] }) #DatabaseCleaner.strategy = :deletion, {pre_count: true, reset_ids:false, :except => %w[instruments genres icecast_server_groups jamcompany jamisp geoipblocks geoipisp geoiplocations cities regions countries] }
DatabaseCleaner.clean_with(:deletion, {pre_count: true, reset_ids:false, :except => %w[instruments genres icecast_server_groups jamcompany jamisp geoipblocks geoipisp geoiplocations cities regions countries] })
end end
config.before(:each) do config.before(:each) do
@ -137,9 +139,9 @@ Spork.prefork do
} }
end end
end end
end #end
Spork.each_run do #Spork.each_run do
# This code will be run each time you run your specs. # This code will be run each time you run your specs.
end #end

View File

@ -0,0 +1,160 @@
ISO3166_COUNTRYCODE_INDEX = 0
ISO3166_COUNTRYNAME_INDEX = 1
REGIONCODES_COUNTRYCODE_INDEX = 0
REGIONCODES_REGIONCODE_INDEX = 1
REGIONCODES_REGIONNAME_INDEX = 2
GEOIPBLOCKS_BEGINIP_INDEX = 0
GEOIPBLOCKS_ENDIP_INDEX = 1
GEOIPBLOCKS_LOCID_INDEX = 2
GEOIPLOCATIONS_LOCID_INDEX = 0
GEOIPLOCATIONS_COUNTRY_INDEX = 1
GEOIPLOCATIONS_REGION_INDEX = 2
GEOIPLOCATIONS_CITY_INDEX = 3
GEOIPLOCATIONS_POSTALCODE_INDEX = 4
GEOIPLOCATIONS_LATITUDE_INDEX = 5
GEOIPLOCATIONS_LONGITUDE_INDEX = 6
GEOIPLOCATIONS_METROCODE_INDEX = 7
GEOIPLOCATIONS_AREACODE_INDEX = 8
GEOIPISP_BEGINIP_INDEX = 0
GEOIPISP_ENDIP_INDEX = 1
GEOIPISP_COMPANY_INDEX = 2
JAMISP_BEGINIP_INDEX = 0
JAMISP_ENDIP_INDEX = 1
JAMISP_COMPANY_INDEX = 2
# the goal is to specify just enough data to build out a score (a 'leaf' in maxmind data)
def tiny_maxmind_dataset
region_codes = [
["US","TX","Texas"]
]
iso3166 = [
["US", "United States"]
]
# table=max_mind_isp
geo_ip_isp_142 = [
["1.0.0.0","1.0.0.255","US","Google"],
["1.0.1.0","1.0.1.255","US","Time Warner"],
["1.0.2.0","1.0.2.255","US","AT&T"]
]
# table=max_mind_geo
geo_ip_city_139 = [
["1.0.0.0","1.0.0.255","US","TX","Austin","78759","30.4000","-97.7528","635","512"], # original: 4.15.0.0, 4.15.0.255 (68091904, 68092159), locid=1504
["1.0.1.0","1.0.1.255","US","TX","Austin","78701","30.2678","-97.7426","635","512"], # original: 4.28.169.0, 4.28.169.255 (68987136, 68987391), locid=1102
["1.0.2.0","1.0.2.255","US","TX","Austin","78729","30.4549","-97.7565","635","512"] # original: 4.30.69.0, 4.30.69.127 (69092608, 69092735), locid=14655
]
# table=geoipblocks, file=GeoIPCity-134-Blocks.csv
geo_ip_city_134_blocks = [
[68091904, 68092159, 1504],
[68987136, 68987391, 1102],
[69092608, 69092735, 14655]
]
# table=geoiplocations, file=GeoIpCity-134-Locations.csv
geo_ip_city_134_locations = [
[1504,"US","TX","Austin","78759",30.4000,-97.7528,635,512],
[1102,"US","TX","Austin","78701",30.2678,-97.7426,635,512],
[14655,"US","TX","Austin","78729",30.4549,-97.7565,635,512]
]
#table=geoipisp
geo_ip_isp = [
[401604608,401866751,"Time Warner Cable"]
]
{
region_codes: region_codes,
iso3166: iso3166,
geo_ip_isp_142: geo_ip_isp_142,
geo_ip_city_139: geo_ip_city_139,
geo_ip_city_134_blocks: geo_ip_city_134_blocks,
geo_ip_city_134_locations: geo_ip_city_134_locations,
geo_ip_isp: geo_ip_isp
}
end
def write_content_to_tmp_file(name, content, prefix = '')
file = Tempfile.new([name.to_s, '.csv'])
File.open(file, 'w') {|f| f.write(to_csv(content, prefix)) }
file
end
def dataset_to_tmp_files(dataset=tiny_maxmind_dataset)
tmp_files = {}
geo_ip_isp_124 = write_content_to_tmp_file(:geo_ip_isp, dataset[:geo_ip_isp])
tmp_files[:geo_ip_124_files] = { 'GeoIPISP.csv' => geo_ip_isp_124 }
geo_ip_isp_134_blocks = write_content_to_tmp_file(:geo_ip_city_134_blocks, dataset[:geo_ip_city_134_blocks],
"Copyright (c) 2011 MaxMind Inc. All Rights Reserved.\n" +
"startIpNum,endIpNum,locId\n")
geo_ip_isp_134_locations = write_content_to_tmp_file(:geo_ip_city_134_locations, dataset[:geo_ip_city_134_locations],
"Copyright (c) 2012 MaxMind LLC. All Rights Reserved.\n" +
"locId,country,region,city,postalCode,latitude,longitude,metroCode,areaCode\n")
tmp_files[:geo_ip_134_files] = { 'GeoIPCity-134-Blocks.csv' => geo_ip_isp_134_blocks , 'GeoIPCity-134-Location.csv' => geo_ip_isp_134_locations }
tmp_files[:region_codes] = write_content_to_tmp_file(:region_codes, dataset[:region_codes])
tmp_files[:iso3166] = write_content_to_tmp_file(:iso3166, dataset[:iso3166])
tmp_files
end
# to be used with maxmind datasets (should be an array of arrays)
def to_csv(content, prefix = '')
buffer = prefix
count = 0
while count < content.length
buffer += content[count].to_csv
count = count + 1
end
buffer[0..buffer.length-2] # take off last trailing \n
end
# from here: http://stackoverflow.com/questions/2204058/show-which-columns-an-index-is-on-in-postgresql
def list_indexes(table_name)
result = GeoIpBlocks.connection.execute("select
i.relname as index_name,
array_to_string(array_agg(a.attname), ', ') as column_names
from
pg_class t,
pg_class i,
pg_index ix,
pg_attribute a
where
t.oid = ix.indrelid
and i.oid = ix.indexrelid
and a.attrelid = t.oid
and a.attnum = ANY(ix.indkey)
and t.relkind = 'r'
and t.relname = '#{table_name}'
group by
t.relname,
i.relname
order by
t.relname,
i.relname;")
result.values.map { |row| row[0] }
end
def table_exists?(table_name)
GeoIpBlocks.connection.select_value("SELECT 1
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = 'public'
AND c.relname = '#{table_name}'");
end
def create_phony_database
GeoIpBlocks.connection.execute("select generate_scores_dataset()").check
end

View File

@ -101,6 +101,14 @@ def app_config
def max_mind_working_dir def max_mind_working_dir
'tmp' 'tmp'
end end
def max_track_upload_failures
10
end
def max_track_part_upload_failures
3
end
private private
def audiomixer_workspace_path def audiomixer_workspace_path

View File

@ -294,7 +294,7 @@
// make the 3 slower requests, which only matter if the user wants to affect their ISP or location // make the 3 slower requests, which only matter if the user wants to affect their ISP or location
api.getCountriesx() api.getCountries()
.done(function(countriesx) { populateCountriesx(countriesx["countriesx"], userDetail.country); } ) .done(function(countriesx) { populateCountriesx(countriesx["countriesx"], userDetail.country); } )
.fail(app.ajaxError) .fail(app.ajaxError)
.always(function() { loadingCountriesData = false; }) .always(function() { loadingCountriesData = false; })

View File

@ -273,7 +273,7 @@
nilOption.text(nilOptionText); nilOption.text(nilOptionText);
countrySelect.append(nilOption); countrySelect.append(nilOption);
rest.getCountriesx().done(function (response) { rest.getCountries().done(function (response) {
$.each(response["countriesx"], function (index, countryx) { $.each(response["countriesx"], function (index, countryx) {
if (!countryx.countrycode) return; if (!countryx.countrycode) return;
var option = $(nilOptionStr); var option = $(nilOptionStr);

View File

@ -469,21 +469,6 @@
}); });
} }
function getCountriesx() {
return $.ajax('/api/countriesx', {
dataType : 'json'
});
}
function getIsps(options) {
var country = options["country"]
return $.ajax('/api/isps', {
data : { country: country},
dataType : 'json'
});
}
function getResolvedLocation() { function getResolvedLocation() {
return $.ajax('/api/resolved_location', { return $.ajax('/api/resolved_location', {
dataType: 'json' dataType: 'json'
@ -1207,8 +1192,6 @@
this.getCities = getCities; this.getCities = getCities;
this.getRegions = getRegions; this.getRegions = getRegions;
this.getCountries = getCountries; this.getCountries = getCountries;
this.getCountriesx = getCountriesx;
this.getIsps = getIsps;
this.getResolvedLocation = getResolvedLocation; this.getResolvedLocation = getResolvedLocation;
this.getInstruments = getInstruments; this.getInstruments = getInstruments;
this.getGenres = getGenres; this.getGenres = getGenres;

View File

@ -476,6 +476,7 @@
function primePumpTimeout(data) { function primePumpTimeout(data) {
clearPrimeGuard(); clearPrimeGuard();
scoring = false; scoring = false;
logger.debug("the prime pump routine timed out")
primeDeferred.reject(); primeDeferred.reject();
} }

View File

@ -3,13 +3,7 @@ class ApiMaxmindRequestsController < ApiController
respond_to :json respond_to :json
def countries def countries
raise "no longer supported, use countriesx" countriesx = MaxMindManager.countries
#countries = MaxMindManager.countries()
#render :json => { :countries => countries }, :status => 200
end
def countriesx
countriesx = MaxMindManager.countriesx()
render :json => { :countriesx => countriesx }, :status => 200 render :json => { :countriesx => countriesx }, :status => 200
end end
@ -31,18 +25,9 @@ class ApiMaxmindRequestsController < ApiController
end end
end end
def isps
isps = MaxMindManager.isps(params[:country])
if isps && isps.length > 0
render :json => { :isps => isps }, :status => 200
else
render :json => { :message => "Unrecognized Country" }, :status => 422
end
end
# returns location hash (country, region, state) based on requesting IP # returns location hash (country, region, state) based on requesting IP
def resolved_location def resolved_location
location = MaxMindManager.lookup(request.remote_ip) location = GeoIpLocations.lookup(request.remote_ip)
render :json => { :country => location[:country], :region => location[:state], :city => location[:city] }, :status => 200 render :json => { :country => location[:country], :region => location[:state], :city => location[:city] }, :status => 200
end end

View File

@ -466,13 +466,13 @@ JS
@location = location @location = location
if @location.nil? if @location.nil?
@location = MaxMindManager.lookup(remote_ip) @location = GeoIpLocations.lookup(remote_ip)
end end
@location[:country] = "US" if @location[:country].nil? @location[:country] = "US" if @location[:country].nil?
# right now we only accept US signups for beta # right now we only accept US signups for beta
@countriesx = MaxMindManager.countriesx() @countriesx = MaxMindManager.countries
# populate regions based on current country # populate regions based on current country
@regions = MaxMindManager.regions(@location[:country]) @regions = MaxMindManager.regions(@location[:country])
@cities = @location[:state].nil? ? [] : MaxMindManager.cities(@location[:country], @location[:state]) @cities = @location[:state].nil? ? [] : MaxMindManager.cities(@location[:country], @location[:state])

View File

@ -245,5 +245,9 @@ if defined?(Bundler)
config.ftue_maximum_gear_latency = 20 config.ftue_maximum_gear_latency = 20
config.max_mind_working_dir = 'tmp' config.max_mind_working_dir = 'tmp'
# recording upload/download configs
config.max_track_upload_failures = 10
config.max_track_part_upload_failures = 3
end end
end end

View File

@ -23,6 +23,7 @@ test: &test
host: localhost host: localhost
pool: 5 pool: 5
timeout: 5000 timeout: 5000
min_messages: warning
production: production:
adapter: postgresql adapter: postgresql

View File

@ -371,10 +371,8 @@ SampleApp::Application.routes.draw do
# Location lookups # Location lookups
match '/countries' => 'api_maxmind_requests#countries', :via => :get match '/countries' => 'api_maxmind_requests#countries', :via => :get
match '/countriesx' => 'api_maxmind_requests#countriesx', :via => :get
match '/regions' => 'api_maxmind_requests#regions', :via => :get match '/regions' => 'api_maxmind_requests#regions', :via => :get
match '/cities' => 'api_maxmind_requests#cities', :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 match '/resolved_location' => 'api_maxmind_requests#resolved_location', :via => :get
# Recordings # Recordings

View File

@ -3,181 +3,33 @@ class MaxMindManager < BaseManager
def initialize(options={}) def initialize(options={})
super(options) super(options)
end end
# Returns a hash with location information. Fields are nil if they can't be figured.
# This is a class method because it doesn't need to be in a transaction.
def self.lookup(ip_address)
city = state = country = nil
locid = ispid = 0
unless ip_address.nil? || ip_address !~ /^\d+\.\d+\.\d+\.\d+$/ def self.countries
#ActiveRecord::Base.connection_pool.with_connection do |connection|
# pg_conn = connection.instance_variable_get("@connection")
# ip_as_int = ip_address_to_int(ip_address)
# pg_conn.exec("SELECT country, region, city FROM max_mind_geo WHERE ip_start <= $1 AND $2 <= ip_end limit 1", [ip_as_int, ip_as_int]) do |result|
# if !result.nil? && result.ntuples > 0
# country = result[0]['country']
# state = result[0]['region']
# city = result[0]['city']
# end
# end
#end
addr = ip_address_to_int(ip_address)
block = GeoIpBlocks.lookup(addr)
if block
locid = block.locid
location = GeoIpLocations.lookup(locid)
if location
# todo translate countrycode to country, region(code) to region
country = location.countrycode
state = location.region
city = location.city
end
end
isp = JamIsp.lookup(addr)
if isp
ispid = isp.coid
end
end
{city: city, state: state, country: country, addr: addr, locidispid: locid*1000000+ispid}
end
def self.lookup_isp(ip_address)
isp = nil
unless ip_address.nil? || ip_address !~ /^\d+\.\d+\.\d+\.\d+$/
ActiveRecord::Base.connection_pool.with_connection do |connection|
pg_conn = connection.instance_variable_get("@connection")
ip_as_int = ip_address_to_int(ip_address)
pg_conn.exec("SELECT isp FROM max_mind_isp WHERE ip_bottom <= $1 AND $2 <= ip_top limit 1", [ip_as_int, ip_as_int]) do |result|
if !result.nil? && result.ntuples > 0
isp = result.getvalue(0, 0)
end
end
end
end
return isp
end
def self.countries()
#ActiveRecord::Base.connection_pool.with_connection do |connection|
# pg_conn = connection.instance_variable_get("@connection")
# pg_conn.exec("SELECT DISTINCT country FROM max_mind_geo ORDER BY country ASC").map do |tuple|
# tuple["country"]
# end
#end
raise "no longer supported, use countriesx"
# returns ordered array of Country objects (countrycode, countryname)
#Country.get_all.map { |c| c.countrycode }
end
def self.countriesx()
#ActiveRecord::Base.connection_pool.with_connection do |connection|
# pg_conn = connection.instance_variable_get("@connection")
# pg_conn.exec("SELECT DISTINCT country FROM max_mind_geo ORDER BY country ASC").map do |tuple|
# tuple["country"]
# end
#end
# returns ordered array of Country objects (countrycode, countryname)
Country.get_all.map { |c| {countrycode: c.countrycode, countryname: c.countryname} } Country.get_all.map { |c| {countrycode: c.countrycode, countryname: c.countryname} }
end end
def self.regions(country) def self.regions(country)
#ActiveRecord::Base.connection_pool.with_connection do |connection|
# pg_conn = connection.instance_variable_get("@connection")
# pg_conn.exec("SELECT DISTINCT region FROM max_mind_geo WHERE country = $1 ORDER BY region ASC", [country]).map do |tuple|
# tuple["region"]
# end
#end
# returns an ordered array of Region objects (region, regionname, countrycode)
Region.get_all(country).map { |r| { region: r.region, name: r.regionname } } Region.get_all(country).map { |r| { region: r.region, name: r.regionname } }
end end
def self.cities(country, region) def self.cities(country, region)
#ActiveRecord::Base.connection_pool.with_connection do |connection|
# pg_conn = connection.instance_variable_get("@connection")
# pg_conn.exec("SELECT DISTINCT city FROM max_mind_geo WHERE country = $1 AND region = $2 ORDER BY city ASC", [country, region]).map do |tuple|
# tuple["city"]
# end
#end
# returns an ordered array of City (city, region, countrycode)
City.get_all(country, region).map { |c| c.city } City.get_all(country, region).map { |c| c.city }
end end
def self.create_phony_database
def self.isps(country) GeoIpBlocks.connection.execute("select generate_scores_dataset()").check
ActiveRecord::Base.connection_pool.with_connection do |connection|
pg_conn = connection.instance_variable_get("@connection")
pg_conn.exec("SELECT DISTINCT isp FROM max_mind_isp WHERE country = $1 ORDER BY isp ASC", [country]).map do |tuple|
tuple["isp"]
end
end
end
# Note that there's one big country, and then two cities in each region.
def create_phony_database()
clear_location_table
(0..255).each do |top_octet|
@pg_conn.exec("INSERT INTO max_mind_geo (ip_start, ip_end, country, region, city, lat, lng) VALUES ($1, $2, $3, $4, $5, 0, 0)",
[
self.class.ip_address_to_int("#{top_octet}.0.0.0"),
self.class.ip_address_to_int("#{top_octet}.255.255.255"),
"US",
['AB', 'BC', 'CD', 'DE'][top_octet % 4],
"City #{top_octet}"
]).clear
end
clear_isp_table
(0..255).each do |top_octet|
@pg_conn.exec("INSERT INTO max_mind_isp (ip_bottom, ip_top, isp, country) VALUES ($1, $2, $3, $4)",
[
self.class.ip_address_to_int("#{top_octet}.0.0.0"),
self.class.ip_address_to_int("#{top_octet}.255.255.255"),
"ISP #{top_octet}",
"US"
]).clear
end
@pg_conn.exec "DELETE FROM cities"
@pg_conn.exec "INSERT INTO cities (city, region, countrycode) SELECT DISTINCT city, region, country FROM max_mind_geo"
@pg_conn.exec "DELETE FROM regions"
@pg_conn.exec "INSERT INTO regions (region, regionname, countrycode) select distinct region, region, countrycode from cities"
@pg_conn.exec "DELETE FROM countries"
@pg_conn.exec "INSERT INTO countries (countrycode, countryname) SELECT DISTINCT countrycode, countrycode FROM regions"
end end
private private
# Make an IP address into an int (bigint)
def self.ip_address_to_int(ip)
ip.split('.').inject(0) {|total,value| (total << 8 ) + value.to_i}
end
def clear_location_table def clear_location_table
@pg_conn.exec("DELETE FROM max_mind_geo").clear @pg_conn.exec("DELETE FROM geoiplocations").clear
end end
def clear_isp_table def clear_isp_table
@pg_conn.exec("DELETE FROM max_mind_isp").clear @pg_conn.exec("DELETE FROM geoispip").clear
end end
end end

View File

@ -9,17 +9,13 @@ namespace :db do
release = MaxMindRelease.order('released_at DESC').first release = MaxMindRelease.order('released_at DESC').first
end end
release.import if release.imported && ENV['REIMPORT'] != '1'
end puts "The MaxMindRelease for #{release.released_at} has already been imported."
puts "If you really want to import it again, specify REIMPORT=1"
return
end
desc "Import a maxmind geo (139) database; run like this: rake db:import_maxmind_geo file=<path_to_GeoIPCity.csv>" release.import(ENV['FORCE_FROM_SOURCE'] == '1')
task import_maxmind_geo: :environment do
MaxMindGeo.import_from_max_mind ENV['file']
end
desc "Import a maxmind isp (142) database; run like this: rake db:import_maxmind_isp file=<path_to_GeoIPISP-142.csv>"
task import_maxmind_isp: :environment do
MaxMindIsp.import_from_max_mind ENV['file']
end end
desc "Import a maxmind blocks (134) database; run like this: rake db:import_geoip_blocks file=<path_to_GeoIPCity-134-Blocks.csv>" desc "Import a maxmind blocks (134) database; run like this: rake db:import_geoip_blocks file=<path_to_GeoIPCity-134-Blocks.csv>"
@ -49,6 +45,7 @@ namespace :db do
desc "Help" desc "Help"
task help: :environment do task help: :environment do
puts "bundle exec rake db:import_maxmind"
puts "bundle exec rake db:import_maxmind_isp file=/path/to/GeoIPISP-142.csv # geo-142" puts "bundle exec rake db:import_maxmind_isp file=/path/to/GeoIPISP-142.csv # geo-142"
puts "bundle exec rake db:import_maxmind_geo file=/path/to/GeoIPCity.csv # geo-139" puts "bundle exec rake db:import_maxmind_geo file=/path/to/GeoIPCity.csv # geo-139"
puts "bundle exec rake db:import_geoip_blocks file=/path/to/GeoIPCity-134-Blocks.csv # geo-134" puts "bundle exec rake db:import_geoip_blocks file=/path/to/GeoIPCity-134-Blocks.csv # geo-134"
@ -61,7 +58,7 @@ namespace :db do
desc "Create a fake set of maxmind data" desc "Create a fake set of maxmind data"
task phony_maxmind: :environment do task phony_maxmind: :environment do
MaxMindManager.active_record_transaction do |manager| MaxMindManager.active_record_transaction do |manager|
manager.create_phony_database() MaxMindManager.create_phony_database
end end
end end
end end

View File

@ -35,7 +35,7 @@ class UserManager < BaseManager
raise PermissionError, "Signups are currently disabled" raise PermissionError, "Signups are currently disabled"
end end
loc = MaxMindManager.lookup(remote_ip) loc = GeoIpLocations.lookup(remote_ip)
# there are three cases here: if location is missing, we'll auto set the city, etc. from # there are three cases here: if location is missing, we'll auto set the city, etc. from
# the ip address; if location is present, empty or not empty, we'll set the city, etc. from # the ip address; if location is present, empty or not empty, we'll set the city, etc. from
# what is present in location. we should NOT normally default city, etc. for the user, they # what is present in location. we should NOT normally default city, etc. for the user, they
@ -77,7 +77,7 @@ class UserManager < BaseManager
def signup_confirm(signup_token, remote_ip=nil) def signup_confirm(signup_token, remote_ip=nil)
begin begin
user = User.signup_confirm(signup_token) user = User.signup_confirm(signup_token)
user.location = MaxMindManager.lookup(remote_ip) if remote_ip user.location = GeoIpLocations.lookup(remote_ip) if remote_ip
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
user = nil user = nil
end end

View File

@ -251,16 +251,6 @@ FactoryGirl.define do
end end
factory :geocoder, :class => JamRuby::MaxMindGeo do
country 'US'
sequence(:region) { |n| ['NC', 'CA'][(n-1).modulo(2)] }
sequence(:city) { |n| ['Apex', 'San Francisco'][(n-1).modulo(2)] }
sequence(:ip_start) { |n| ['1.1.0.0', '1.1.255.255'][(n-1).modulo(2)] }
sequence(:ip_end) { |n| ['1.2.0.0', '1.2.255.255'][(n-1).modulo(2)] }
sequence(:lat) { |n| [35.73265, 37.7742075][(n-1).modulo(2)] }
sequence(:lng) { |n| [-78.85029, -122.4155311][(n-1).modulo(2)] }
end
factory :icecast_limit, :class => JamRuby::IcecastLimit do factory :icecast_limit, :class => JamRuby::IcecastLimit do
clients 5 clients 5
sources 1 sources 1
@ -518,6 +508,7 @@ FactoryGirl.define do
factory :rsvp_request, class: JamRuby::RsvpRequest do factory :rsvp_request, class: JamRuby::RsvpRequest do
canceled false canceled false
cancel_all false cancel_all false
association :user, :factory => :user
# creates *number* slots for a new rsvp_request # creates *number* slots for a new rsvp_request
factory :rsvp_request_for_multiple_slots do factory :rsvp_request_for_multiple_slots do

View File

@ -5,15 +5,7 @@ describe "Bands", :js => true, :type => :feature, :capybara_feature => true do
subject { page } subject { page }
before(:all) do before(:all) do
Capybara.javascript_driver = :poltergeist
Capybara.current_driver = Capybara.javascript_driver
Capybara.default_wait_time = 15 Capybara.default_wait_time = 15
# MaxMindIsp.delete_all # prove that city/state/country will remain nil if no maxmind data
# MaxMindGeo.delete_all
#MaxMindManager.active_record_transaction do |manager|
# manager.create_phony_database()
#end
end end
let(:fan) { FactoryGirl.create(:fan) } let(:fan) { FactoryGirl.create(:fan) }

View File

@ -1,43 +1,29 @@
require 'spec_helper' require 'spec_helper'
# these tests avoid the use of ActiveRecord and FactoryGirl to do blackbox, non test-instrumented tests
describe MaxMindManager do describe MaxMindManager do
before(:each) do before(:each) do
@maxmind_manager = MaxMindManager.new(:conn => @conn) @maxmind_manager = MaxMindManager.new(:conn => @conn)
MaxMindManager.active_record_transaction do |manager| MaxMindManager.create_phony_database
manager.create_phony_database()
end
end end
it "looks up countries successfully" do it "looks up countries successfully" do
countries = MaxMindManager.countriesx() countries = MaxMindManager.countries
countries.length.should == 1 countries.length.should == 1
countries[0] == {countrycode: "US", countryname: "United States"} countries[0] == {countrycode: "US", countryname: "United States"}
end end
it "looks up regions successfully" do it "looks up regions successfully" do
regions = MaxMindManager.regions("US") regions = MaxMindManager.regions("US")
regions.length.should == 4 regions.length.should == 11
regions.first[:region].should == "AB"
regions.last[:region].should == "DE"
end end
it "looks up cities successfully" do it "looks up cities successfully" do
cities = MaxMindManager.cities("US", "AB") cities = MaxMindManager.cities("US", "TX")
cities.length.should == 64 cities.length.should == 4
cities.first.should == "City 0" cities.first.should == "Austin"
cities.last.should == "City 96" cities.last.should == "San Antonio"
end end
it "looks up isp successfully" do
isp = MaxMindManager.lookup_isp("127.0.0.1")
isp.should == "ISP 127"
end
it "looks up isp-by-country succesfully" do
isps = MaxMindManager.isps("US")
isps.length.should == 256 # because the phone_database method creates 256 isps, all in US
end
end end

View File

@ -187,8 +187,7 @@ describe UserManager do
} }
it "signup successfully" do it "signup successfully" do
MaxMindIsp.delete_all # prove that city/state/country will remain nil if no maxmind data GeoIpLocations.delete_all # prove that city/state/country will remain nil if no maxmind data
MaxMindGeo.delete_all
user = @user_manager.signup(remote_ip: "127.0.0.1", user = @user_manager.signup(remote_ip: "127.0.0.1",
first_name: "bob", first_name: "bob",
@ -207,9 +206,9 @@ describe UserManager do
user.last_name.should == "smith" user.last_name.should == "smith"
user.email.should == "userman1@jamkazam.com" user.email.should == "userman1@jamkazam.com"
user.email_confirmed.should be_false user.email_confirmed.should be_false
user.city.should == 'Boston' user.city.should be_nil
user.state.should == 'MA' user.state.should be_nil
user.country.should == 'US' user.country.should be_nil
user.instruments.length.should == 1 user.instruments.length.should == 1
user.subscribe_email.should be_true user.subscribe_email.should be_true
user.signup_token.should_not be_nil user.signup_token.should_not be_nil
@ -257,9 +256,7 @@ describe UserManager do
end end
it "sets the location properly from maxmind" do it "sets the location properly from maxmind" do
MaxMindManager.active_record_transaction do |manager| MaxMindManager.create_phony_database
manager.create_phony_database()
end
user = @user_manager.signup(remote_ip: "127.0.0.1", user = @user_manager.signup(remote_ip: "127.0.0.1",
first_name: "bob", first_name: "bob",
last_name: "smith", last_name: "smith",
@ -278,9 +275,7 @@ describe UserManager do
end end
it "accepts location if specified" do it "accepts location if specified" do
MaxMindManager.active_record_transaction do |manager| MaxMindManager.create_phony_database
manager.create_phony_database()
end
user = @user_manager.signup(remote_ip: "127.0.0.1", user = @user_manager.signup(remote_ip: "127.0.0.1",
first_name: "bob", first_name: "bob",
last_name: "smith", last_name: "smith",
@ -300,9 +295,7 @@ describe UserManager do
end end
it "accepts a nil location, if specified" do it "accepts a nil location, if specified" do
MaxMindManager.active_record_transaction do |manager| MaxMindManager.create_phony_database
manager.create_phony_database()
end
user = @user_manager.signup(remote_ip: "127.0.0.1", user = @user_manager.signup(remote_ip: "127.0.0.1",
first_name: "bob", first_name: "bob",
last_name: "smith", last_name: "smith",
@ -323,9 +316,7 @@ describe UserManager do
it "accepts birth_date if specified" do it "accepts birth_date if specified" do
MaxMindManager.active_record_transaction do |manager| MaxMindManager.create_phony_database
manager.create_phony_database()
end
user = @user_manager.signup(remote_ip: "127.0.0.1", user = @user_manager.signup(remote_ip: "127.0.0.1",
first_name: "bob", first_name: "bob",
last_name: "smith", last_name: "smith",

View File

@ -46,6 +46,14 @@ def web_config
def max_audio_downloads def max_audio_downloads
10 10
end end
def max_track_upload_failures
10
end
def max_track_part_upload_failures
3
end
end end
klass.new klass.new
end end