diff --git a/cli.js b/cli.js index 8049b2b..4cd5f50 100644 --- a/cli.js +++ b/cli.js @@ -4,7 +4,10 @@ var packageApi = require('./lib/package'); var credentials = require('./credentials'); var fs = require('fs'); +var mongoose = require('mongoose'); +var uri = 'mongodb://localhost/packagetracker'; +mongoose.connect(uri); module.exports = { packageApi: packageApi, diff --git a/lib/package.js b/lib/package.js index a0e137a..4186989 100644 --- a/lib/package.js +++ b/lib/package.js @@ -7,15 +7,50 @@ var fedexApi = require('shipping-fedex'); var upsApi = require('shipping-ups'); var uspsApi = require('shipping-usps'); -var credentials = require('../credentials').shippingProviders; +var credentials = require('../credentials');//.shippingProviders; -var fedex = new fedexApi(credentials.fedex); -var ups = new upsApi(credentials.ups); -var usps = new uspsApi(credentials.usps); +var fedex = new fedexApi(credentials.shippingProviders.fedex); +var ups = new upsApi(credentials.shippingProviders.ups); +var usps = new uspsApi(credentials.shippingProviders.usps); var Package = require('../models/package'); +var Address = require('../models/address'); + +var geocoder = require('node-geocoder')('openstreetmap', 'https'); module.exports = { + getPackageLatLong: function(package, callback) { + var city = this.getCurrentLocation(package); + console.log(city); + if (city) { + Address.findOne({address: city}, function(err, data) { + console.log(err, data); + if (err) { + callback(err, null); + } else { + if (data) { + callback(null, data); + } else { + console.log("Address cache not found. Looking up"); + geocoder.geocode(city, function(err, data) { + if (err) { + callback(err, null); + } else { + console.log(data); + var address = new Address({ + address: city, + geoInfo: data + }); + address.save(callback); + } + }); + } + } + }); + } else { + callback('invalid city', city); + } + }, buildFedexTrackingLink: function(trackingNumber) { return "https://www.fedex.com/apps/fedextrack/?tracknumbers=" + trackingNumber + "&language=en&cntry_code=us"; @@ -105,9 +140,60 @@ module.exports = { } }, + getCurrentLocation: function(package) { + var event; + switch(package.carrier.toLowerCase()) { + case "usps": + try { + event = package.lastResponse.TrackResponse.TrackInfo; + return event.TrackDetail[0].match(/[A-Z][A-Z0-9, ]*$/)[0]; + } catch(e) { + console.error(package.description); + console.error(e); + return null; + } + + break; + case "ups": + try { + event = package.lastResponse.Shipment.Package.Activity[0]; + } catch(e) { + try { + event = package.lastResponse.Shipment.Package.Activity; + } catch(e) { + console.error(package.description); + console.error(e); + return null; + } + } + try { + return event.ActivityLocation.Address.City + ", " + event.ActivityLocation.Address.StateProvinceCode; + } catch(e) { + console.error(package.description); + console.error(e); + return null; + } + break; + case "fedex": + try { + event = package.lastResponse.CompletedTrackDetails[0].TrackDetails[0].StatusDetail; + return event.Location.City + ", " + event.Location.StateOrProvinceCode; + } catch(e) { + console.error(package.description); + console.error(e); + return null; + } + break; + default: + return null; + break; + } + }, + parseFedexTrackingInfo: function(trackingInfo) { try { - return trackingInfo.CompletedTrackDetails[0].TrackDetails[0].StatusDetail.Description; + var status = trackingInfo.CompletedTrackDetails[0].TrackDetails[0].StatusDetail; + return status.Description + " at " + status.Location.City + ", " + status.Location.StateOrProvinceCode; } catch(e) { console.error("Could not parse FedEx package status from: " + JSON.stringify(trackingInfo)); console.error(e.message); @@ -163,12 +249,15 @@ module.exports = { package.lastResponse = data; package.timestamps.lastUpdated = Date.now(); package.timestamps.nextUpdate = (new Date().setHours(new Date().getHours() + 3)); - package.save(function(err, data) { - console.log("Package " + package._id + " saved."); - callback(err, data); + this.getPackageLatLong(package, function(err, data) { + package.currentLocation = data; + package.save(function(err, data) { + console.log("Package " + package._id + " saved."); + callback(err, data); + }); }); } - }); + }.bind(this)); }, updateAllPackages: function(callback) { diff --git a/models/address.js b/models/address.js new file mode 100644 index 0000000..f83b77f --- /dev/null +++ b/models/address.js @@ -0,0 +1,15 @@ +/** + * Created by matt on 3/20/15. + */ + +var mongoose = require('mongoose'); + +var addressSchema = mongoose.Schema({ + address: String, + geoInfo: Object +}); + +addressSchema.index({"address": 1}); + +var Address = mongoose.model('Address', addressSchema); +module.exports = Address; \ No newline at end of file diff --git a/models/package.js b/models/package.js index d536b8d..23c8890 100644 --- a/models/package.js +++ b/models/package.js @@ -25,7 +25,8 @@ var packageSchema = mongoose.Schema({ update: Boolean, hidden: Boolean }, - lastResponse: Object + lastResponse: Object, + currentLocation: Object }); packageSchema.index({"carrier": 1}); diff --git a/package.json b/package.json index 7de1562..2836882 100755 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "longjohn": "^0.2.4", "mongoose": "^3.8.23", "morgan": "^1.5.1", + "node-geocoder": "^2.19.0", "passport": "^0.2.1", "passport-google-oauth2": "^0.1.6", "serve-favicon": "^2.2.0", diff --git a/public/css/packagetracker.css b/public/css/packagetracker.css index 0599db4..fc8de26 100755 --- a/public/css/packagetracker.css +++ b/public/css/packagetracker.css @@ -32,4 +32,10 @@ body { .revision .subject { display: block; +} + +#map-canvas { + display: block; + width: 100%; + height: 500px; } \ No newline at end of file diff --git a/routes/package.js b/routes/package.js index e08973c..03f1804 100644 --- a/routes/package.js +++ b/routes/package.js @@ -7,6 +7,7 @@ var auth = require('../lib/auth'); var Package = require('../models/package'); var flash = require('../lib/flash'); var packageUtils = require('../lib/package'); +var credentials = require('../credentials'); router.get('/packages', auth.ensureAuthenticated, function(req, res) { var query = { @@ -30,7 +31,7 @@ router.get('/packages', auth.ensureAuthenticated, function(req, res) { data[package].latestEvent = packageUtils.parseTrackingInfo(data[package], data[package].lastResponse); data[package].deliveryEstimate = packageUtils.getDeliveryEstimate(data[package]); } - res.render('packages', {packages: data, csrf: 'blarg'}); + res.render('packages', {packages: data}); } } }); @@ -139,4 +140,25 @@ router.get('/package/:id', auth.ensureAuthenticated, function(req, res) { }); }); +router.get('/map', auth.ensureAuthenticated, function(req, res) { + var query = { + userId: req.user.authId, + 'flags.hidden': false + }; + + Package.find(query, function(err, data) { + if (err) { + res.render('500', {error: err}); + } else { + for(var package in data) { + data[package].location = { + latitude: data[package].currentLocation.geoInfo[0].latitude, + longitude: data[package].currentLocation.geoInfo[0].longitude + }; + } + res.render('map', {packages: data, mapsApiKey: credentials.apiKeys.googleMaps}); + } + }); +}); + module.exports = router; diff --git a/views/layouts/main.handlebars b/views/layouts/main.handlebars index 6295f0d..2cb3c8b 100755 --- a/views/layouts/main.handlebars +++ b/views/layouts/main.handlebars @@ -11,6 +11,7 @@ + {{{ _sections.header }}} @@ -31,6 +32,7 @@
  • User
  • Packages
  • +
  • Map
  • diff --git a/views/map.handlebars b/views/map.handlebars new file mode 100644 index 0000000..ba6dd22 --- /dev/null +++ b/views/map.handlebars @@ -0,0 +1,40 @@ +
    + +{{#section 'header'}} + +{{/section}} + +{{#section 'jquery'}} + +{{/section}} \ No newline at end of file