diff --git a/Vagrantfile b/Vagrantfile index 03ae93c5e..ba232863a 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,7 +1,7 @@ # -*- mode: ruby -*- # vi: set ft=ruby : -Vagrant.require_version ">= 1.5" +Vagrant.require_version ">= 2.0" require "yaml" CAC_SHARED_FOLDER_TYPE = ENV.fetch("CAC_SHARED_FOLDER_TYPE", "nfs") @@ -57,7 +57,7 @@ def install_dependent_roles ansible_roles_spec = File.join(ansible_directory, "roles.yml") YAML.load_file(ansible_roles_spec).each do |role| - role_name = role["src"] + role_name = role["name"] ? role["name"] : role["src"] role_version = role["version"] role_path = File.join(ansible_directory, "roles", role_name) galaxy_metadata = galaxy_install_info(role_name) @@ -111,6 +111,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| database.ssh.forward_x11 = true database.vm.provision "ansible" do |ansible| + ansible.compatibility_mode = "2.0" ansible.playbook = "deployment/ansible/database.yml" ansible.inventory_path = ANSIBLE_INVENTORY_PATH ansible.raw_arguments = ["--timeout=60"] @@ -148,6 +149,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| app.ssh.forward_x11 = true app.vm.provision "ansible" do |ansible| + ansible.compatibility_mode = "2.0" ansible.playbook = "deployment/ansible/app.yml" ansible.inventory_path = ANSIBLE_INVENTORY_PATH ansible.raw_arguments = ["--timeout=60"] @@ -177,6 +179,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| otp.ssh.forward_x11 = true otp.vm.provision "ansible" do |ansible| + ansible.compatibility_mode = "2.0" ansible.playbook = "deployment/ansible/otp.yml" ansible.inventory_path = ANSIBLE_INVENTORY_PATH ansible.raw_arguments = ["--timeout=60"] diff --git a/deployment/ansible/group_vars/all b/deployment/ansible/group_vars/all index 82d64e30b..7fd2e34f9 100644 --- a/deployment/ansible/group_vars/all +++ b/deployment/ansible/group_vars/all @@ -1,16 +1,19 @@ --- +java_version: "8u*" +java_major_version: "8" + app_username: "vagrant" -packer_version: "0.7.5" +packer_version: "1.0.2" -nodejs_version: 6.11.4 +nodejs_version: 8.10.0 virtualenv_version: 15.1.0 otp_router: "default" # used by nginx and gunicorn to set timeouts; OTP defaults to 30s -otp_session_timeout_s: 30 +otp_session_timeout_s: 90 s3_otp_data: cleanair-otp-data diff --git a/deployment/ansible/roles.yml b/deployment/ansible/roles.yml index 37a48d2e5..6f56f5550 100644 --- a/deployment/ansible/roles.yml +++ b/deployment/ansible/roles.yml @@ -1,14 +1,8 @@ -- src: azavea.git - version: 0.1.0 - -- src: azavea.java - version: 0.2.6 - - src: azavea.opentripplanner - version: 1.0.8 + version: 1.1.0 - src: azavea.nginx - version: 0.2.2 + version: 0.3.1 - src: azavea.nodejs version: 0.4.0 @@ -17,7 +11,7 @@ version: 0.2.0 - src: azavea.papertrail - version: 1.1.1 + version: 1.2.0 - src: azavea.pip version: 1.0.0 diff --git a/deployment/ansible/roles/cac-tripplanner.app/defaults/main.yml b/deployment/ansible/roles/cac-tripplanner.app/defaults/main.yml index 804ba4bfc..e4d874577 100644 --- a/deployment/ansible/roles/cac-tripplanner.app/defaults/main.yml +++ b/deployment/ansible/roles/cac-tripplanner.app/defaults/main.yml @@ -19,15 +19,16 @@ root_media_dir: "/media/cac" cac_python_dependencies: - { name: 'base58', version: '0.2.5' } - { name: 'boto', version: '2.48.0' } - - { name: 'django', version: '1.11.7' } + - { name: 'django', version: '1.11.12' } - { name: 'django-ckeditor', version: '5.3.1' } - - { name: 'django-extensions', version: '1.9.7' } + - { name: 'django-extensions', version: '1.9.9' } - { name: 'django-storages', version: '1.6.5' } - { name: 'gunicorn', version: '19.7.1' } - - { name: 'pillow', version: '4.3.0' } - - { name: 'psycopg2', version: '2.7.3' } - - { name: 'pytz', version: '2017.3' } + - { name: 'Pillow', version: '5.1.0' } + - { name: 'psycopg2', version: '2.7.4' } + - { name: 'pytz', version: '2018.4' } - { name: 'pyyaml', version: '3.12' } - - { name: 'troposphere', version: '0.7.2'} + - { name: 'troposphere', version: '1.8.1' } + - { name: 'majorkirby', version: '0.2.1' } # Note: django-wpadmin is installed manually to work around the fact that ansible-pip # ignores editable=False diff --git a/deployment/ansible/roles/cac-tripplanner.app/tasks/dev-test-dependencies.yml b/deployment/ansible/roles/cac-tripplanner.app/tasks/dev-test-dependencies.yml index eb012b463..bb6bb1c7b 100644 --- a/deployment/ansible/roles/cac-tripplanner.app/tasks/dev-test-dependencies.yml +++ b/deployment/ansible/roles/cac-tripplanner.app/tasks/dev-test-dependencies.yml @@ -2,4 +2,4 @@ - name: Install dev/test python packages pip: name={{ item.name }} version={{ item.version }} with_items: - - { name: 'flake8', version: '3.4.1' } + - { name: 'flake8', version: '3.5.0' } diff --git a/deployment/ansible/roles/cac-tripplanner.app/tasks/main.yml b/deployment/ansible/roles/cac-tripplanner.app/tasks/main.yml index 27546739c..c1bb8999f 100644 --- a/deployment/ansible/roles/cac-tripplanner.app/tasks/main.yml +++ b/deployment/ansible/roles/cac-tripplanner.app/tasks/main.yml @@ -21,15 +21,6 @@ - name: Install django-wpadmin manually to work around ansible bug command: pip install --upgrade 'git+https://github.com/azavea/django-wpadmin@v1.11#egg=django-wpadmin' -# TODO: #914 replace major kirby -# TODO: peg this to a version, rather than a commit, when released -# ansible pip module installs this in /tmp/src for some reason, so we use the -# command instead -- name: Install majorkirby - command: pip install "git+https://github.com/azavea/majorkirby@7688e19e61bf9d218c03a2af6d469d0626b86918#egg=majorkirby" - creates=/usr/local/lib/python2.7/dist-packages/majorkirby/__init__.py - when: develop - - name: Touch log file and set permissions file: path={{ app_log }} state=touch owner={{ app_username }} group={{ app_username }} mode=0664 @@ -81,6 +72,6 @@ template: src=nginx-default.j2 dest=/etc/nginx/sites-available/default notify: Restart nginx -- { include: jslibs.yml } +- { import_tasks: jslibs.yml } -- { include: dev-test-dependencies.yml, when: develop or test } +- { import_tasks: dev-test-dependencies.yml, when: develop or test } diff --git a/deployment/ansible/roles/cac-tripplanner.otp-data/templates/router-config.json.j2 b/deployment/ansible/roles/cac-tripplanner.otp-data/templates/router-config.json.j2 index e93089812..88d3d731a 100644 --- a/deployment/ansible/roles/cac-tripplanner.otp-data/templates/router-config.json.j2 +++ b/deployment/ansible/roles/cac-tripplanner.otp-data/templates/router-config.json.j2 @@ -1,4 +1,5 @@ { + timeout: {{ otp_session_timeout_s }}, updaters: [ { type: "bike-rental", diff --git a/deployment/cloudformation/app.py b/deployment/cloudformation/app.py index 8ffdae501..d9de4fdfd 100644 --- a/deployment/cloudformation/app.py +++ b/deployment/cloudformation/app.py @@ -370,15 +370,17 @@ def set_up_stack(self): LoadBalancerNames=[Ref(app_server_load_balancer)], MaxSize=Ref(self.param_max_size), MinSize=Ref(self.param_min_size), - NotificationConfiguration=asg.NotificationConfiguration( - TopicARN=Ref(self.param_notification_arn), - NotificationTypes=[ - asg.EC2_INSTANCE_LAUNCH, - asg.EC2_INSTANCE_LAUNCH_ERROR, - asg.EC2_INSTANCE_TERMINATE, - asg.EC2_INSTANCE_TERMINATE_ERROR - ] - ), + NotificationConfigurations=[ + asg.NotificationConfigurations( + TopicARN=Ref(self.param_notification_arn), + NotificationTypes=[ + asg.EC2_INSTANCE_LAUNCH, + asg.EC2_INSTANCE_LAUNCH_ERROR, + asg.EC2_INSTANCE_TERMINATE, + asg.EC2_INSTANCE_TERMINATE_ERROR + ] + ) + ], VPCZoneIdentifier=Ref(self.param_private_subnets), Tags=[ asg.Tag('Name', '{}Server'.format(self.STACK_NAME_PREFIX), True), diff --git a/deployment/packer/cac.json b/deployment/packer/cac.json index 805772508..7e2ec815f 100644 --- a/deployment/packer/cac.json +++ b/deployment/packer/cac.json @@ -78,8 +78,9 @@ "mkdir -p {{user `ansible_staging_directory`}}", "mkdir -p {{user `intermediate_directory`}}", "sudo apt-get -y install build-essential python-dev python-pip git", + "sudo pip install --upgrade pip", "sudo pip install paramiko==1.16.0", - "sudo pip install ansible==2.1.0.0" + "sudo pip install ansible==2.4.2.0" ] }, { @@ -105,6 +106,7 @@ "playbook_file": "{{user `local_project_directory`}}/deployment/ansible/app.yml", "inventory_file": "{{user `local_project_directory`}}/deployment/ansible/hosts/hosts.app", "group_vars": "{{user `local_project_directory`}}/deployment/ansible/group_vars/", + "staging_directory": "{{user `ansible_staging_directory`}}", "extra_arguments": [ "--user 'ubuntu'" ], @@ -115,6 +117,7 @@ "playbook_file": "{{user `local_project_directory`}}/deployment/ansible/otp.yml", "inventory_file": "{{user `local_project_directory`}}/deployment/ansible/hosts/hosts.otp", "group_vars": "{{user `local_project_directory`}}/deployment/ansible/group_vars/", + "staging_directory": "{{user `ansible_staging_directory`}}", "extra_arguments": [ "--user 'ubuntu'" ], diff --git a/deployment/packer/cac_packer.py b/deployment/packer/cac_packer.py index 8289df1b2..3200ed71a 100644 --- a/deployment/packer/cac_packer.py +++ b/deployment/packer/cac_packer.py @@ -63,7 +63,7 @@ def run_packer(machine_type, region, creds): env = os.environ.copy() env['AWS_ACCESS_KEY_ID'] = creds['aws_access_key_id'] env['AWS_SECRET_ACCESS_KEY'] = creds['aws_secret_access_key'] - env['AWS_SECURITY_TOKEN'] = creds['aws_security_token'] + env['AWS_SESSION_TOKEN'] = creds['aws_security_token'] packer_template_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'cac.json') packer_command = ['packer', 'build', diff --git a/python/cac_tripplanner/destinations/views.py b/python/cac_tripplanner/destinations/views.py index e36f90237..fb4fa0872 100644 --- a/python/cac_tripplanner/destinations/views.py +++ b/python/cac_tripplanner/destinations/views.py @@ -225,7 +225,7 @@ def isochrone(self, payload): try: # get a feature collection json_poly = json.loads(isochrone_response.content) - except: + except: # noqa: E722 # No isochrone found. Is GTFS loaded? Is origin within the graph bounds? json_poly = json.loads("{}") return json_poly diff --git a/python/cac_tripplanner/templates/base.html b/python/cac_tripplanner/templates/base.html index 879c35202..513fa0d63 100644 --- a/python/cac_tripplanner/templates/base.html +++ b/python/cac_tripplanner/templates/base.html @@ -16,23 +16,27 @@ + + {% endblock %} {% block extrametatags %} + + + content="{% if request.is_secure %}https{% else %}http{% endif %}://{{ request.META.HTTP_HOST }}/" /> - - - - + + + + {% endblock %} {% include "partials/ios-weblinks.html" %} @@ -109,6 +113,7 @@ + diff --git a/python/cac_tripplanner/templates/event-detail.html b/python/cac_tripplanner/templates/event-detail.html index 959043703..b288570c6 100644 --- a/python/cac_tripplanner/templates/event-detail.html +++ b/python/cac_tripplanner/templates/event-detail.html @@ -1,4 +1,3 @@ - {% extends "base.html" %} {% load staticfiles %} @@ -7,22 +6,27 @@ + + + {% endblock %} {% block extrametatags %} + + - - - - + content="{% if request.is_secure %}https{% else %}http{% endif %}://{{ request.META.HTTP_HOST }}/" /> + - + + + + {% endblock %} {% block content %} diff --git a/python/cac_tripplanner/templates/learn-detail.html b/python/cac_tripplanner/templates/learn-detail.html index 860820745..e6e2c5963 100644 --- a/python/cac_tripplanner/templates/learn-detail.html +++ b/python/cac_tripplanner/templates/learn-detail.html @@ -6,22 +6,27 @@ + + + {% endblock %} {% block extrametatags %} + + - - - - + - + + + + {% endblock %} {% block content %} diff --git a/python/cac_tripplanner/templates/place-detail.html b/python/cac_tripplanner/templates/place-detail.html index 36b56171c..850b49331 100644 --- a/python/cac_tripplanner/templates/place-detail.html +++ b/python/cac_tripplanner/templates/place-detail.html @@ -1,4 +1,3 @@ - {% extends "base.html" %} {% load staticfiles %} @@ -7,22 +6,27 @@ + + + {% endblock %} {% block extrametatags %} + + - - - - + content="{% if request.is_secure %}https{% else %}http{% endif %}://{{ request.META.HTTP_HOST }}/" /> - + + + + + {% endblock %} {% block content %} diff --git a/python/cac_tripplanner/templates/service-worker.js b/python/cac_tripplanner/templates/service-worker.js index f235bdea3..469541b6c 100644 --- a/python/cac_tripplanner/templates/service-worker.js +++ b/python/cac_tripplanner/templates/service-worker.js @@ -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_v7'; +var CACHE_NAME = 'cac_tripplanner_v9'; var cacheFiles = {{ cache_files | safe }}; @@ -16,6 +16,9 @@ self.addEventListener('install', function(event) { }); self.addEventListener('fetch', function(event) { + if (event.request.cache === 'only-if-cache') { + event.request.mode = 'same-origin'; + } return fetch(event.request); // do not use cache }); diff --git a/src/app/scripts/cac/control/cac-control-explore.js b/src/app/scripts/cac/control/cac-control-explore.js index 33cad9b6b..47d1bc36c 100644 --- a/src/app/scripts/cac/control/cac-control-explore.js +++ b/src/app/scripts/cac/control/cac-control-explore.js @@ -240,6 +240,18 @@ CAC.Control.Explore = (function (_, $, MapTemplates, HomeTemplates, Places, Rout ); } + function enableSlider(doEnable) { + if (doEnable) { + $(options.selectors.isochroneSliderContainer).removeClass('disabled'); + $(options.selectors.isochroneSlider).removeClass('disabled'); + } else { + $(options.selectors.isochroneSliderContainer).addClass('disabled'); + $(options.selectors.isochroneSlider).addClass('disabled'); + } + $(options.selectors.isochroneSliderContainer).prop('disabled', !doEnable); + $(options.selectors.isochroneSlider).prop('disabled', !doEnable); + } + function setError(message) { if (tabControl.isTabShowing(tabControl.TABS.EXPLORE)) { var $alert = $(MapTemplates.alert(message, 'Cannot show travelshed', 'danger')); @@ -258,6 +270,7 @@ CAC.Control.Explore = (function (_, $, MapTemplates, HomeTemplates, Places, Rout if (key === 'origin' && exploreLatLng) { showSpinner(); exploreLatLng = null; + enableSlider(false); mapControl.clearDirectionsMarker('origin'); clearIsochrone(); // get all places in sidebar when no origin set @@ -297,8 +310,10 @@ CAC.Control.Explore = (function (_, $, MapTemplates, HomeTemplates, Places, Rout if (tabControl.isTabShowing(tabControl.TABS.EXPLORE)) { mapControl.setDirectionsMarkers(exploreLatLng); } + enableSlider(true); } else { exploreLatLng = null; + enableSlider(false); clearIsochrone(); } } @@ -325,6 +340,7 @@ CAC.Control.Explore = (function (_, $, MapTemplates, HomeTemplates, Places, Rout setAddress(exploreOrigin); } else { exploreLatLng = null; + enableSlider(false); } } @@ -364,31 +380,27 @@ CAC.Control.Explore = (function (_, $, MapTemplates, HomeTemplates, Places, Rout } } - // Now places list has been updated, go fetch the travel time to each - // from the new origin to each place. - var promises = Places.getTimesToPlaces(destinations, exploreLatLng); - $.when.apply($, promises).always(function() { - - // order the destinations by travel time - destinations = _.sortBy(destinations, ['duration']); - var places = HomeTemplates.destinations(destinations, - text, - filter, - tabControl.isTabShowing(tabControl.TABS.HOME)); - $(options.selectors.placesContent).html(places); - // send event that places content changed - events.trigger(eventNames.destinationsLoaded); - - // also draw all destinations on explore map that match the category filter - // (not just those in the isochrone) - if (tabControl.isTabShowing(tabControl.TABS.EXPLORE) && mapControl.isLoaded()) { - // allDestinations has been loaded by now - mapControl.isochroneControl.drawDestinations(filterPlacesCategory(allDestinations), - destinations); - } - - showPlacesContent(); - }); + // get distance from origin to each place + destinations = Places.getDistancesToPlaces(destinations, exploreLatLng); + // order the destinations by distance + destinations = _.sortBy(destinations, ['distance']); + + var places = HomeTemplates.destinations(destinations, + text, + filter, + tabControl.isTabShowing(tabControl.TABS.HOME)); + $(options.selectors.placesContent).html(places); + // send event that places content changed + events.trigger(eventNames.destinationsLoaded); + + // also draw all destinations on explore map that match the category filter + // (not just those in the isochrone) + if (tabControl.isTabShowing(tabControl.TABS.EXPLORE) && mapControl.isLoaded()) { + // allDestinations has been loaded by now + mapControl.isochroneControl.drawDestinations(filterPlacesCategory(allDestinations), + destinations); + } + showPlacesContent(); } // Given desintations from the FindReachableDestinations app endpoint, diff --git a/src/app/scripts/cac/home/cac-home-templates.js b/src/app/scripts/cac/home/cac-home-templates.js index 2d66f2088..b19ec794a 100644 --- a/src/app/scripts/cac/home/cac-home-templates.js +++ b/src/app/scripts/cac/home/cac-home-templates.js @@ -113,7 +113,7 @@ CAC.Home.Templates = (function (Handlebars, moment) { '{{#unless alternateMessage}}', '