Skip to content
This repository was archived by the owner on Dec 14, 2023. It is now read-only.

Commit 0864a2b

Browse files
authored
Backfilling of Dojos locations (#419)
* Backfilling of Dojos * Functional v1 but slow * Use the proper handler for errors * Ensure adminLvl exists before assigning it
1 parent 48c09eb commit 0864a2b

File tree

4 files changed

+280
-8
lines changed

4 files changed

+280
-8
lines changed

dojos.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ module.exports = function (options) {
207207

208208
// One shot
209209
seneca.add({role: plugin, cmd: 'backfill_champions'}, cmd_backfill_champions);
210+
seneca.add({role: plugin, cmd: 'backfill_dojo_county_state'}, require('./lib/backfill-dojo-county-state'));
210211
seneca.add({role: plugin, cmd: 'migrate-v1-leads'}, require('./lib/migrate-old-lead'));
211212

212213
if (options.kue && options.kue.start) {
@@ -1447,8 +1448,8 @@ module.exports = function (options) {
14471448

14481449
function cmd_reverse_geocode (args, done) {
14491450
var coords = args.coords;
1450-
14511451
geocoder.reverse(coords, function (err, res) {
1452+
if (!res) res = {};
14521453
if (err) res.error = err;
14531454
done(null, res);
14541455
});

lib/backfill-dojo-county-state.js

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
(function () {
2+
'use strict';
3+
4+
var seneca = require('seneca');
5+
var async = require('async');
6+
/**
7+
* Retrieve all existing dojos and leads and setup the state and county when the address exists
8+
* @return
9+
* @example curl -d '{"role": "cd-dojos", "cmd":"backfill_dojo_county_state"}' http://localhost:10301/act
10+
*/
11+
function cmd_backfill_state_county (args, done) {
12+
var seneca = this;
13+
function backfillDojo (wfCb) {
14+
console.time('backfill_dojos');
15+
seneca.act({role: 'cd-dojos', cmd: 'list', query: { } }, function (err, dojos) {
16+
async.eachSeries(dojos, function (d, sCb) {
17+
if (d.geoPoint) {
18+
geocode(d.geoPoint, function (err, res) {
19+
if (err) return done(err);
20+
d = formatGeocoded(d, res);
21+
seneca.act({ role: 'cd-dojos', entity: 'dojo', cmd: 'save',
22+
dojo: { id: d.id, state: d.state, county: d.county, city: d.city }
23+
}, sCb);
24+
});
25+
} else {
26+
// This isn't normal but we can't care for this scenario
27+
// Blame somebody else
28+
// console.log('Missing geoPoint for', d.name, d.id);
29+
sCb();
30+
}
31+
}, function (err) {
32+
if (err) done(err);
33+
console.timeEnd('backfill_dojos');
34+
});
35+
});
36+
// Early return to avoid seneca's timeout
37+
wfCb();
38+
}
39+
function backfillLead (wfCb) {
40+
console.time('backfill_leads');
41+
seneca.act({role: 'cd-dojos', entity: 'lead', cmd: 'list', query: { } }, function (err, leads) {
42+
async.eachSeries(leads, function (l, sCb) {
43+
if (l.application && l.application.venue && l.application.venue.geoPoint) {
44+
var venue = l.application.venue || { isValid: false, visited: false };
45+
geocode(venue.geoPoint, function (err, res) {
46+
if (err) return done(err);
47+
venue = formatGeocoded(venue, res);
48+
seneca.act({ role: 'cd-dojos', entity: 'lead', cmd: 'save',
49+
dojoLead: { id: l.id, application: l.application }
50+
}, sCb);
51+
});
52+
} else {
53+
// It's fine, it's optional at that stage
54+
// console.log('Missing geoPoint for lead ', l.email, l.id);
55+
sCb();
56+
}
57+
}, function (err) {
58+
if (err) done(err);
59+
console.timeEnd('backfill_leads');
60+
});
61+
});
62+
// Early return to avoid seneca's timeout
63+
wfCb();
64+
}
65+
function formatGeocoded(entity, res) {
66+
if (res.error) {
67+
if (res.error.message = 'Status is ZERO_RESULTS.') {
68+
return entity;
69+
}
70+
throw res.error;
71+
}
72+
var geocoded = res[0];
73+
// Assign from the bottom up: city -> county (-> state if possible)
74+
var administrativeLevelsSize = Object.values(geocoded.administrativeLevels).length;
75+
entity.county = {};
76+
entity.state = {};
77+
var adminLvl1 = {};
78+
var adminLvl2 = {};
79+
if (administrativeLevelsSize === 0) {
80+
// See https://github.com/nchaulet/node-geocoder/issues/264
81+
var address_comps = res.raw.results.reduce(function (acc, r) {
82+
acc = acc.concat(r.address_components)
83+
return acc;
84+
}, []);
85+
adminLvl1 = address_comps.find(function (ac) { return ac.types.indexOf('administrative_area_level_1') > -1 });
86+
adminLvl2 = address_comps.find(function (ac) { return ac.types.indexOf('administrative_area_level_2') > -1 });
87+
}
88+
if ((geocoded.administrativeLevels.level2long && geocoded.administrativeLevels.level1long) || (adminLvl1 && adminLvl1.long_name && adminLvl2 && adminLvl2.long_name)) {
89+
entity.county = { name: geocoded.administrativeLevels.level2long || adminLvl2.long_name };
90+
entity.state = {
91+
name: geocoded.administrativeLevels.level1long || adminLvl1.long_name,
92+
shortCode: geocoded.administrativeLevels.level1short || adminLvl1.short_name,
93+
};
94+
} else if (geocoded.administrativeLevels.level1long || geocoded.administrativeLevels.level2long) {
95+
entity.county = {
96+
name: geocoded.administrativeLevels.level1long || adminLvl1.long_name || geocoded.administrativeLevels.level2long,
97+
shortCode: geocoded.administrativeLevels.level1short || adminLvl1.short_name || geocoded.administrativeLevels.level2short,
98+
};
99+
}
100+
entity.city = { name: geocoded.city || geocoded.extra.neighborhood };
101+
return entity;
102+
}
103+
function geocode(coords, cb) {
104+
seneca.act({role: 'cd-dojos', cmd: 'reverse_geocode', coords, raw: true }, cb);
105+
}
106+
async.parallel([
107+
backfillDojo,
108+
backfillLead,
109+
], function (err){
110+
console.log('done');
111+
if (err) return done(err);
112+
return done();
113+
});
114+
}
115+
116+
module.exports = cmd_backfill_state_county;
117+
})();

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
"lodash": "^4.6",
5959
"moment": "2.10.3",
6060
"newrelic": "2.4.2",
61-
"node-geocoder": "2.23.0",
61+
"node-geocoder": "^3.22",
6262
"pg": "5.1.0",
6363
"phoneformat.js": "^1.0.3",
6464
"pkgcloud": "1.3.0",

0 commit comments

Comments
 (0)