Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
flibbertigibbet committed Oct 25, 2017
2 parents 4f9df87 + bca15d7 commit 9089559
Show file tree
Hide file tree
Showing 95 changed files with 331 additions and 5,336 deletions.
5 changes: 1 addition & 4 deletions deployment/ansible/group_vars/all
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,12 @@ app_username: "vagrant"

packer_version: "0.7.5"

nodejs_version: 6.11.0
nodejs_version: 6.11.4

virtualenv_version: 15.1.0

otp_router: "default"

otp_version: "1.2.0"
otp_jar_sha1: "a7f659a63a54e894457bab6fc162fb0f47586057"

# used by nginx and gunicorn to set timeouts; OTP defaults to 30s
otp_session_timeout_s: 30

Expand Down
2 changes: 1 addition & 1 deletion deployment/ansible/roles.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
version: 0.2.6

- src: azavea.opentripplanner
version: 1.0.6
version: 1.0.7

- src: azavea.nginx
version: 0.2.2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ cac_python_dependencies:
- { name: 'boto', version: '2.48.0' }
- { name: 'django', version: '1.8.18' }
- { name: 'django-ckeditor', version: '5.3.0' }
- { name: 'django-extensions', version: '1.9.0' }
- { name: 'django-storages-redux', version: '1.3.3' }
- { name: 'django-extensions', version: '1.9.1' }
- { name: 'django-storages', version: '1.6.5' }
- { name: 'gunicorn', version: '19.7.1' }
- { name: 'pillow', version: '4.2.1' }
- { name: 'pillow', version: '4.3.0' }
- { name: 'psycopg2', version: '2.7.3' }
- { name: 'pytz', version: '2017.2' }
- { name: 'pyyaml', version: '3.12' }
Expand Down
17 changes: 15 additions & 2 deletions python/cac_tripplanner/cac_tripplanner/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def test_isochrone_partitioning(self):
# use current date for query
dt = datetime.now()
day_str = str(dt.date())
isochrone_start = '/map/reachable?fromPlace=39.954688%2C-75.204677&mode%5B%5D=WALK%2DTRANSIT&time=7%3A30am&cutoffSec=5000&maxWalkDistance=5000'
isochrone_start = '/map/reachable?fromPlace=39.954688%2C-75.204677&mode%5B%5D=WALK%2DTRANSIT&time=7%3A30am&cutoffSec=3600&maxWalkDistance=5000'
isochrone_url = ('{start}&date={day_str}').format(start=isochrone_start, day_str=day_str)
response = self.client.get(isochrone_url)
json_response = json.loads(response.content)
Expand All @@ -80,7 +80,7 @@ def test_empty_isochrone(self):
dt = datetime.now()
day_str = str(dt.date())

isochrone_start = '/map/reachable?fromPlace=79.954688%2D-45.204677&mode%5B%5D=WALK%2DTRANSIT&time=7%3A30am&cutoffSec=5000&maxWalkDistance=5000'
isochrone_start = '/map/reachable?fromPlace=79.954688%2D-45.204677&mode%5B%5D=WALK%2DTRANSIT&time=7%3A30am&cutoffSec=2000&maxWalkDistance=5000'
isochrone_url = ('{start}&date={day_str}').format(start=isochrone_start, day_str=day_str)

response = self.client.get(isochrone_url)
Expand All @@ -89,3 +89,16 @@ def test_empty_isochrone(self):
self.assertEqual(0, len(matched))
isochrone = json_response['isochrone']
self.assertEqual({}, isochrone)

def test_isochrone_outside_range(self):
"""Return error if cutoffSec parameter is outside allowed range"""

# use current date for query
dt = datetime.now()
day_str = str(dt.date())

isochrone_start = '/map/reachable?fromPlace=79.954688%2D-45.204677&mode%5B%5D=WALK%2DTRANSIT&time=7%3A30am&cutoffSec=9000&maxWalkDistance=5000'
isochrone_url = ('{start}&date={day_str}').format(start=isochrone_start, day_str=day_str)

response = self.client.get(isochrone_url)
self.assertEqual(400, response.status_code)
66 changes: 34 additions & 32 deletions python/cac_tripplanner/destinations/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,33 @@ def image_to_url(dest_dict, field_name):
return image.url if image else ''


def set_destination_properties(destination):
"""Helper for adding and converting properties in serializing destinations as JSON
:param destination: Destination model object
:returns: Dictionary representation of object, with added properties
"""
obj = model_to_dict(destination)
obj['address'] = obj['name']
obj['image'] = image_to_url(obj, 'image')
obj['wide_image'] = image_to_url(obj, 'wide_image')
obj['point'] = json.loads(obj['point'].json)
# convert to format like properties on ESRI geocoder results
x = obj['point']['coordinates'][0]
y = obj['point']['coordinates'][1]
obj['extent'] = {'xmax': x, 'xmin': x, 'ymax': y, 'ymin': y}
obj['location'] = {'x': x, 'y': y}
obj['attributes'] = {
'City': obj['city'],
'Postal': obj['zip'],
'Region': obj['state'],
'StAddr': obj['address']
}
return obj


class FindReachableDestinations(View):
"""Class based view for fetching isochrone and finding destinations of interest within it"""
# TODO: make decisions on acceptable ranges of values that this endpoint will support

otp_router = 'default'
isochrone_url = settings.ISOCHRONE_URL
Expand Down Expand Up @@ -166,6 +190,12 @@ def get(self, request, *args, **kwargs):
Return both the isochrone GeoJSON and the list of matched destinations."""
params = request.GET.copy() # make mutable

# allow a max travelshed size of 60 minutes in a query
cutoff_sec = int(params.get('cutoffSec', -1))
if not cutoff_sec or cutoff_sec < 0 or cutoff_sec > 3600:
return HttpResponse(status=400,
reason='cutoffSec must be greater than 0 and less than 360')

json_poly = self.isochrone(params)

# Have a FeatureCollection of MultiPolygons
Expand All @@ -174,18 +204,14 @@ def get(self, request, *args, **kwargs):
for poly in json_poly['features']:
geom_str = json.dumps(poly['geometry'])
geom = GEOSGeometry(geom_str)
matched_objects = (Destination.objects.filter(published=True)
matched_objects = (Destination.objects.filter(published=True, point__within=geom)
.distance(geom)
.order_by('distance'))
else:
matched_objects = []

# make locations JSON serializable
matched_objects = [model_to_dict(x) for x in matched_objects]
for obj in matched_objects:
obj['point'] = json.loads(obj['point'].json)
obj['image'] = image_to_url(obj, 'image')
obj['wide_image'] = image_to_url(obj, 'wide_image')
matched_objects = [set_destination_properties(x) for x in matched_objects]

response = {'matched': matched_objects, 'isochrone': json_poly}
return HttpResponse(json.dumps(response), 'application/json')
Expand Down Expand Up @@ -239,31 +265,7 @@ def get(self, request, *args, **kwargs):
return HttpResponse(error, 'application/json')
results = results[:limit_int]

data = [model_to_dict(x) for x in results]
for obj in data:
obj['address'] = obj['name']
obj['point'] = json.loads(obj['point'].json)
obj['image'] = image_to_url(obj, 'image')
obj['wide_image'] = image_to_url(obj, 'wide_image')
# convert to format like properties on ESRI geocoder results
extent = {
'xmax': obj['point']['coordinates'][0],
'xmin': obj['point']['coordinates'][0],
'ymax': obj['point']['coordinates'][1],
'ymin': obj['point']['coordinates'][1]
}
obj['extent'] = extent
obj['attributes'] = {
'City': obj['city'],
'Postal': obj['zip'],
'Region': obj['state'],
'StAddr': obj['address']
}

obj['location'] = {
'x': obj['point']['coordinates'][0],
'y': obj['point']['coordinates'][1]
}
data = [set_destination_properties(x) for x in results]

response = {'destinations': data}
return HttpResponse(json.dumps(response), 'application/json')
Expand Down
2 changes: 1 addition & 1 deletion python/cac_tripplanner/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@

{% block jsimports %}

<script type="text/javascript" src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
jQuery.noConflict(); // because JotForms.
</script>
Expand Down
2 changes: 1 addition & 1 deletion python/cac_tripplanner/templates/service-worker.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Service Worker to support functioning as a PWA
// https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers

var CACHE_NAME = 'cac_tripplanner_v2';
var CACHE_NAME = 'cac_tripplanner_v3';

var cacheFiles = {{ cache_files | safe }};

Expand Down
10 changes: 6 additions & 4 deletions scripts/lint.sh
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
#!/bin/bash

function mark_unstable {
java -jar jenkins-cli.jar -s $JENKINS_URI set-build-result unstable
java -jar jenkins-cli.jar -s "$JENKINS_URI set-build-result unstable"
}

set -x
trap 'mark_unstable' ERR

# Python linting
vagrant ssh app -c "flake8 /opt/app/python --exclude=migrations"
# run twice to get console output and to write to file
vagrant ssh app -c "flake8 /opt/app/python --exclude=migrations --output-file=/opt/app/python/violations.txt"
# first remove contents of violations file, as it will not get overwritten if there are no warnings
vagrant ssh app -c "touch /opt/app/python/violations.txt"
# get console output and to write to file
vagrant ssh app -c "flake8 /opt/app/python --exclude=migrations \
--output-file=/opt/app/python/violations.txt --exit-zero --tee"

# Run JS linting
vagrant ssh app -c "cd /opt/app/src && npm run gulp-lint"
Expand Down
54 changes: 48 additions & 6 deletions src/app/scripts/cac/control/cac-control-directions.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ CAC.Control.Directions = (function (_, $, moment, Control, Geocoder, Routing, Te

var defaults = {
selectors: {
directions: '.directions-results',
hiddenClass: 'hidden',
itineraryBlock: '.route-summary',
places: '.places',
selectedItineraryClass: 'selected',
spinner: '.directions-results > .sk-spinner'
spinner: '.directions-results > .sk-spinner',
visible: ':visible'
}
};
var options = {};
Expand All @@ -29,6 +32,7 @@ CAC.Control.Directions = (function (_, $, moment, Control, Geocoder, Routing, Te

var mapControl = null;
var itineraryControl = null;
var exploreControl = null;
var tabControl = null;
var urlRouter = null;
var directionsFormControl = null;
Expand All @@ -39,6 +43,7 @@ CAC.Control.Directions = (function (_, $, moment, Control, Geocoder, Routing, Te
options = $.extend({}, defaults, params);
mapControl = options.mapControl;
tabControl = options.tabControl;
exploreControl = options.exploreControl;
itineraryControl = mapControl.itineraryControl;
urlRouter = options.urlRouter;
directionsFormControl = options.directionsFormControl;
Expand Down Expand Up @@ -96,6 +101,7 @@ CAC.Control.Directions = (function (_, $, moment, Control, Geocoder, Routing, Te
* Throttled to cut down on requests.
*/
var planTrip = _.throttle(function() { // jshint ignore:line
showPlaces(false);
if (!(directions.origin && directions.destination)) {
directionsFormControl.setError('origin');
directionsFormControl.setError('destination');
Expand Down Expand Up @@ -172,6 +178,7 @@ CAC.Control.Directions = (function (_, $, moment, Control, Geocoder, Routing, Te
setFromUserPreferences();
} else {
clearDirections();
showPlaces(true);
}
}

Expand All @@ -188,11 +195,23 @@ CAC.Control.Directions = (function (_, $, moment, Control, Geocoder, Routing, Te
}

function showSpinner() {
showPlaces(false);
itineraryListControl.hide();
directionsListControl.hide();
$(options.selectors.spinner).removeClass(options.selectors.hiddenClass);
}

// helper to call plan trip if a destination is set, or show places list if no destination
function planTripOrShowPlaces() {
if (directions.destination) {
showPlaces(false);
planTrip();
} else {
showPlaces(true);
exploreControl.getNearbyPlaces();
}
}

/**
* Get parameters to pass to OpenTripPlanner, based on current settings
*
Expand Down Expand Up @@ -234,6 +253,8 @@ CAC.Control.Directions = (function (_, $, moment, Control, Geocoder, Routing, Te
}

function onDirectionsBackClicked() {
// show directions list again
showPlaces(false);
// show the other itineraries again
itineraryListControl.showItineraries(true);
currentItinerary.highlight(true);
Expand All @@ -246,6 +267,9 @@ CAC.Control.Directions = (function (_, $, moment, Control, Geocoder, Routing, Te
* Handles click events to select a given itinerary
*/
function onItineraryClicked(event, itinerary) {
// hide both the directions list and the places list
$(options.selectors.directions).hide();
$(options.selectors.places).hide();
if (itinerary) {
// hide all other itineraries
itineraryListControl.showItineraries(false);
Expand Down Expand Up @@ -301,13 +325,14 @@ CAC.Control.Directions = (function (_, $, moment, Control, Geocoder, Routing, Te
*/
function queryWithWaypoints(event, points) {
UserPreferences.setPreference('waypoints', points.waypoints);
showPlaces(false);
planTrip();
}

// trigger re-query when trip options update
function setOptions() {
if (tabControl.isTabShowing(tabControl.TABS.DIRECTIONS)) {
planTrip();
planTripOrShowPlaces();
}
}

Expand All @@ -326,7 +351,7 @@ CAC.Control.Directions = (function (_, $, moment, Control, Geocoder, Routing, Te
}

// update the directions for the reverse trip
planTrip();
planTripOrShowPlaces();
}

function onTypeaheadCleared(event, key) {
Expand All @@ -335,6 +360,8 @@ CAC.Control.Directions = (function (_, $, moment, Control, Geocoder, Routing, Te

if (tabControl.isTabShowing(tabControl.TABS.DIRECTIONS)) {
mapControl.clearDirectionsMarker(key);
showPlaces(true);
exploreControl.getNearbyPlaces();
}
}

Expand All @@ -345,7 +372,7 @@ CAC.Control.Directions = (function (_, $, moment, Control, Geocoder, Routing, Te
}
setDirections(key, [result.location.y, result.location.x]);
if (tabControl.isTabShowing(tabControl.TABS.DIRECTIONS)) {
planTrip();
planTripOrShowPlaces();
}
}

Expand Down Expand Up @@ -381,6 +408,17 @@ CAC.Control.Directions = (function (_, $, moment, Control, Geocoder, Routing, Te
}
}

// toggles between showing directions tab content or places list (explore mode content)
function showPlaces(doShowPlaces) {
if (doShowPlaces) {
$(options.selectors.directions).hide();
$(options.selectors.places).show();
} else {
$(options.selectors.directions).show();
$(options.selectors.places).hide();
}
}

// Updates the URL to match the currently-selected options
function updateUrl() {
urlRouter.updateUrl(urlRouter.buildDirectionsUrlFromPrefs());
Expand All @@ -402,8 +440,12 @@ CAC.Control.Directions = (function (_, $, moment, Control, Geocoder, Routing, Te
directions.destination = [destination.location.y, destination.location.x ];
}

if (tabControl.isTabShowing(tabControl.TABS.DIRECTIONS) && (origin || destination)) {
planTrip();
if (tabControl.isTabShowing(tabControl.TABS.DIRECTIONS)) {
// get nearby places if no destination has been set yet
planTripOrShowPlaces();
} else {
// explore tab visible
showPlaces(true);
}
}

Expand Down
Loading

0 comments on commit 9089559

Please sign in to comment.