Skip to content

Commit

Permalink
Merge branch 'release/3.0.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
flibbertigibbet committed Dec 9, 2019
2 parents cac622b + 81ef829 commit d4d9da5
Show file tree
Hide file tree
Showing 93 changed files with 4,024 additions and 1,045 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Development Installation
3. Copy `deployment/ansible/group_vars/development_template` to `deployment/ansible/group_vars/development`
4. Run `vagrant up`
5. See the app at http://localhost:8024! See OpenTripPlanner at http://localhost:9090.
6. Running `npm run gulp-watch` from `/opt/app/src` will automatically collect static files together when changes are detected for Django template consumption. Alternatively, `npm run gulp-development` can be run manually whenever changes are made to the static files.
6. Running `./scripts/serve-js-dev.sh` on the host will rebuild the front-end app on file change (the browser must be reloaded manually to pick up the change). Alternatively, `cd /opt/app/src && npm run gulp-development` can be run manually in the VM to pick up changes to the static files.

Note that if there is an existing build Graph.obj in `otp_data`, vagrant provisioning in development mode will not attempt to rebuild the graph, but will use the one already present.

Expand Down
16 changes: 5 additions & 11 deletions deployment/ansible/group_vars/all
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,13 @@ postgres_user: "cac_tripplanner"
postgres_password: "cac_tripplanner"
postgres_host: "192.168.8.25"

packer_version: "1.4.4"

# Python 2 version used where python 2 interpreter needed
python_version: "2.7.*"
postgresql_support_psycopg2_version: "2.8.*"
'postgis_version': [2, 1, 8]

nodejs_version: 12.13.0
nodejs_npm_version: 6.12.0

pip_version: 19.3.*
virtualenv_version: 16.7.7
packer_version: "1.4.4"

otp_version: "1.4.0"
otp_jar_sha1: "0367b1a15bac5f587807a5b897a9734209f8135c"
nodejs_version: 12.13.1
nodejs_npm_version: 6.13.1

otp_router: "default"

Expand Down
11 changes: 1 addition & 10 deletions deployment/ansible/roles.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
- src: azavea.opentripplanner
version: 2.0.0
version: 2.0.1

- src: azavea.nginx
version: 0.3.1
Expand All @@ -13,14 +13,5 @@
- src: azavea.papertrail
version: 2.0.0

- src: azavea.pip
version: 2.0.0

- src: azavea.python
version: 0.1.0

- src: azavea.postgresql-support
version: 0.4.0

- src: azavea.postgresql
version: 1.0.0
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
- name: Install dev/test python packages
pip: name={{ item.name }} version={{ item.version }}
pip: name={{ item.name }} version={{ item.version }} executable=/usr/bin/pip3
with_items:
- { name: 'flake8', version: '3.7.7' }
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
production: False

# Use python 3 on database VM
ansible_python_interpreter: "/usr/bin/python3"
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
---
dependencies:
- { role: "azavea.postgresql" }
- { role: "cac-tripplanner.python3" }
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
state: present
pkg:
- build-essential
- gcc
- libgeos-dev
- libgdal-dev
- libproj-dev
Expand Down
29 changes: 23 additions & 6 deletions deployment/ansible/roles/cac-tripplanner.database/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
---
- name: Install GCC for PostgreSQL support role
- name: Configure the PostgreSQL APT key
apt_key: url=https://www.postgresql.org/media/keys/ACCC4CF8.asc state=present

- name: Configure the PostgreSQL main APT repository
apt_repository: repo="deb http://apt.postgresql.org/pub/repos/apt/ {{ ansible_distribution_release}}-pgdg main"
state=present

- name: Install client API libraries for PostgreSQL
apt:
state: present
pkg: gcc
pkg:
- libpq5={{ postgresql_support_libpq_version }}
- libpq-dev={{ postgresql_support_libpq_version }}

- name: Install PostgreSQL client
apt:
state: latest
pkg:
- postgresql-client-{{ postgresql_version }}

- name: Dynamically include PostgreSQL support role
include_role:
name: azavea.postgresql-support
- name: Install PostgreSQL driver for Python
pip: name=psycopg2
executable=/usr/bin/pip3
version={{ postgresql_support_psycopg2_version }}
state=present

- name: Install PostGIS extension from source
import_tasks: install-postgis-from-source.yml
Expand All @@ -24,7 +41,7 @@

- name: Add PostGIS extension
become_user: postgres
command: psql {{ postgres_db }} -c "CREATE EXTENSION postgis"
command: psql {{ postgres_db }} -c "CREATE EXTENSION IF NOT EXISTS postgis;"
register: psql_result
failed_when: >
psql_result.rc != 0 and ("already exists" not in psql_result.stderr)
Expand Down
8 changes: 3 additions & 5 deletions deployment/packer/cac.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,11 @@
"inline": [
"sleep 10",
"sudo apt-get update",
"sleep 30",
"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 --upgrade setuptools",
"sudo pip install --upgrade paramiko",
"sudo pip install --upgrade ansible"
"sudo apt-get -y install python3-dev python3-pip git",
"sudo -H pip3 install ansible==2.8"
]
},
{
Expand Down
14 changes: 14 additions & 0 deletions python/cac_tripplanner/cac_tripplanner/publish_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from django.utils.translation import ugettext_lazy


class PublishableMixin:
"""Helper to add Django admin actions to publish and unpublish model objects."""
actions = ('make_published', 'make_unpublished')

def make_published(self, request, queryset):
queryset.update(published=True)
make_published.short_description = ugettext_lazy("Publish selected %(verbose_name_plural)s")

def make_unpublished(self, request, queryset):
queryset.update(published=False)
make_unpublished.short_description = ugettext_lazy("Unpublish selected %(verbose_name_plural)s")
3 changes: 3 additions & 0 deletions python/cac_tripplanner/cac_tripplanner/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
# Events
url(r'^event/(?P<pk>[\d-]+)/$', dest_views.event_detail, name='event-detail'),

# Tours
url(r'^tour/(?P<pk>[\d-]+)/$', dest_views.tour_detail, name='tour-detail'),

# About (no more FAQ)
url(r'^(?P<slug>about)/$', cms_views.about_faq, name='about'),

Expand Down
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion python/cac_tripplanner/deployment_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
boto==2.49.0
PyYAML==5.1.2
PyYAML==5.2
majorkirby==1.0.0
requests==2.22.0
troposphere==2.5.2
122 changes: 99 additions & 23 deletions python/cac_tripplanner/destinations/admin.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
import logging
from operator import itemgetter

from django.conf import settings
from django.contrib import admin, gis

from image_cropping import ImageCroppingMixin

from .forms import DestinationForm, EventForm, ExtraImagesForm
from cac_tripplanner.publish_utils import PublishableMixin

from .forms import (DestinationForm,
EventForm,
EventDestinationForm,
ExtraImagesForm,
TourDestinationForm,
TourForm)
from .models import (Destination,
DestinationUserFlags,
EventDestination,
Event,
EventUserFlags,
ExtraDestinationPicture,
ExtraEventPicture)
ExtraEventPicture,
TourDestination,
Tour)

logger = logging.getLogger(__name__)


class ExtraDestinationImagesInline(ImageCroppingMixin, admin.StackedInline):
Expand All @@ -28,11 +43,24 @@ class ExtraEventImagesInline(ImageCroppingMixin, admin.StackedInline):
extra = 0


class DestinationAdmin(ImageCroppingMixin, gis.admin.OSMGeoAdmin):
class EventDestinationsInline(admin.StackedInline):

form = EventDestinationForm
model = EventDestination
extra = 1


class TourDestinationsInline(admin.StackedInline):

form = TourDestinationForm
model = TourDestination
extra = 1


class DestinationAdmin(ImageCroppingMixin, PublishableMixin, gis.admin.OSMGeoAdmin):
form = DestinationForm

list_display = ('name', 'published', 'priority', 'address', 'city', 'state', 'zipcode')
actions = ('make_published', 'make_unpublished')
ordering = ('name', )
"""To change field display order, define them all here.
Default is order defined in model, but due to inheritance, cannot reorder across
Expand Down Expand Up @@ -69,34 +97,69 @@ class DestinationAdmin(ImageCroppingMixin, gis.admin.OSMGeoAdmin):
'/static/scripts/main.js'
]

def make_published(self, request, queryset):
queryset.update(published=True)
make_published.short_description = 'Publish selected destinations'

def make_unpublished(self, request, queryset):
queryset.update(published=False)
make_unpublished.short_description = 'Unpublish selected destinations'


class EventAdmin(ImageCroppingMixin, admin.ModelAdmin):
def save_ordered_formset(form, formset, OrderedDestination, related_field):
"""Helper for normalizing tour and event destination ordering on form save.
:param form: Django form passed to save_formset
:param formset: Django formset passed to save_formset
:param OrderedDestination: Class of related object for destinations with orders
:param related_field: Name of field for this related object on OrderedDestination
"""
# save without committing to be able to delete any removed destinations
formset.save(commit=False)
for obj in formset.deleted_objects:
obj.delete()

# commit save here to assign IDs to any newly added destinations
instances = formset.save(commit=True)

# Normalize the ordering of the destinations
instance_id = form.instance.id
# get a list of dicts with 'order' and related 'id' properties
filter_kwargs = {'{fld}'.format(fld=related_field): instance_id}
last_destinations = list(OrderedDestination.objects.filter(
**filter_kwargs).values('id', 'order'))
# Retain the current formset order as a third dict property
for formset_order, dest in enumerate(last_destinations):
dest['formset_order'] = formset_order

# Update the order with any changed formset value
for instance in instances:
for d in last_destinations:
if d['id'] == instance.id:
d['order'] = instance.order
break

# Sort destinations by 1) newly assigned order then 2) last (formset) order.
# This means multiple destinations given the same order will be ordered
# secondarily based on their position in the inline formset, top to bottom.
resorted = sorted(last_destinations, key=itemgetter('order', 'formset_order'))

# Reassign order values so that they are normalized to
# start at 1, increment by 1, and not repeat or skip any integers.
for normalized_order, dest in enumerate(resorted):
new_order = normalized_order + 1
# update objects that need their order changed
if dest['order'] != new_order:
OrderedDestination.objects.filter(id=dest['id']).update(order=new_order)

form.save_m2m()


class EventAdmin(ImageCroppingMixin, PublishableMixin, admin.ModelAdmin):
form = EventForm

fields = ('name', 'website_url', 'description', 'image', 'image_raw', 'wide_image',
'wide_image_raw', 'published', 'priority', 'accessible', 'activities',
'start_date', 'end_date', 'destination')
'start_date', 'end_date', )
list_display = ('name', 'published', 'priority', )
actions = ('make_published', 'make_unpublished', )
ordering = ('name', )

inlines = [ExtraEventImagesInline]

def make_published(self, request, queryset):
queryset.update(published=True)
make_published.short_description = 'Publish selected events'
inlines = [ExtraEventImagesInline, EventDestinationsInline]

def make_unpublished(self, request, queryset):
queryset.update(published=False)
make_unpublished.short_description = 'Unpublish selected events'
def save_formset(self, request, form, formset, change):
save_ordered_formset(form, formset, EventDestination, 'related_event_id')


class AttractionUserFlagsAdmin(admin.ModelAdmin):
Expand All @@ -114,8 +177,21 @@ def has_delete_permission(self, request, obj=None):
return False # hide 'delete' button


class TourAdmin(PublishableMixin, admin.ModelAdmin):

form = TourForm
inlines = [TourDestinationsInline]
list_display = ('name', 'published', 'priority')
ordering = ('name',)

def save_formset(self, request, form, formset, change):
save_ordered_formset(form, formset, TourDestination, 'related_tour_id')


admin.site.register(Destination, DestinationAdmin)
admin.site.register(Event, EventAdmin)

admin.site.register(DestinationUserFlags, AttractionUserFlagsAdmin)
admin.site.register(EventUserFlags, AttractionUserFlagsAdmin)

admin.site.register(Tour, TourAdmin)
2 changes: 1 addition & 1 deletion python/cac_tripplanner/destinations/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@

class DestinationsConfig(AppConfig):
name = 'destinations'
verbose_name = 'Destinations and Events'
verbose_name = 'Destinations, Events, and Tours'
Loading

0 comments on commit d4d9da5

Please sign in to comment.