diff --git a/python/cac_tripplanner/cac_tripplanner/publish_utils.py b/python/cac_tripplanner/cac_tripplanner/publish_utils.py index dbd68d7a1..cd5e8ea2c 100644 --- a/python/cac_tripplanner/cac_tripplanner/publish_utils.py +++ b/python/cac_tripplanner/cac_tripplanner/publish_utils.py @@ -1,14 +1,17 @@ -from django.utils.translation import ugettext_lazy +from django.utils.translation import gettext_lazy class PublishableMixin: """Helper to add Django admin actions to publish and unpublish model objects.""" - actions = ('make_published', 'make_unpublished') + + 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") + + make_published.short_description = gettext_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") + + make_unpublished.short_description = gettext_lazy("Unpublish selected %(verbose_name_plural)s") diff --git a/python/cac_tripplanner/cac_tripplanner/settings.py b/python/cac_tripplanner/cac_tripplanner/settings.py index 6dd5ef409..2a4faa39e 100644 --- a/python/cac_tripplanner/cac_tripplanner/settings.py +++ b/python/cac_tripplanner/cac_tripplanner/settings.py @@ -22,52 +22,49 @@ # Tell image cropping library to use Django admin jquery, # or else loading the image cropper will fail for destinations admin # because it loads jquery for gis.admin.OSMGeoAdmin -IMAGE_CROPPING_JQUERY_URL = '/static/admin/js/vendor/jquery/jquery.js' +IMAGE_CROPPING_JQUERY_URL = "/static/admin/js/vendor/jquery/jquery.js" # https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html # inherit the bucket's ACL AWS_DEFAULT_ACL = None try: - secrets = yaml.safe_load(open('/etc/cac_secrets', 'r')) -except (IOError, NameError): + with open("/etc/cac_secrets", "r") as secrets_file: + secrets = yaml.safe_load(secrets_file) +except (OSError, NameError): # Note: secrets are read in via a YAML file, so make sure nothing is added # here that cannot be represented in YAML. One example is a tuple: represent # it as a list here, and then convert to a tuple later on (see internal_ips). secrets = { - 'secret_key': '%&_DEVELOPMENT_SECRET_KEY_#42*pk!3y6lvk&1psyk=e=pr', - 'database': { - 'ENGINE': 'django.contrib.gis.db.backends.postgis', - 'NAME': 'cac_tripplanner', - 'USER': 'cac_tripplanner', - 'PASSWORD': 'cac_tripplanner', - 'HOST': '192.168.8.25', - 'PORT': '5432' + "secret_key": "%&_DEVELOPMENT_SECRET_KEY_#42*pk!3y6lvk&1psyk=e=pr", + "database": { + "ENGINE": "django.contrib.gis.db.backends.postgis", + "NAME": "cac_tripplanner", + "USER": "cac_tripplanner", + "PASSWORD": "cac_tripplanner", + "HOST": "192.168.8.25", + "PORT": "5432", }, # Note: the OTP URL is called directly from within javascript. In # order to view the page on an external machine, this URL must be # overridden via the secrets file. This can't be automatically set # to the host machine's DNS here, because this code runs in a VM. - 'otp_url': 'http://192.168.8.26/otp/routers/{router}/', - 'internal_ips': ['0.0.0.0', '127.0.0.1'], - 'postgis_version': [2, 5, 2], - 'build_dir': '/opt/app/src', - 'production': False, - + "otp_url": "http://192.168.8.26/otp/routers/{router}/", + "internal_ips": ["0.0.0.0", "127.0.0.1"], + "postgis_version": [2, 5, 2], + "build_dir": "/opt/app/src", + "production": False, # For storing images on s3, set 'use_s3_storage' to True and specify the bucket name. # AWS access key and secret access keys will be obtained via the IAM role. - 'use_s3_storage': False, - 'aws_storage_bucket_name': '', - + "use_s3_storage": False, + "aws_storage_bucket_name": "", # Facebook app ID - 'fb_app_id': '', - + "fb_app_id": "", # API key for posting user flag events - 'user_flag_api_key': '', - - 'default_admin_username': 'admin', - 'default_admin_password': 'admin', - 'default_admin_email': 'systems+cac@azavea.com' + "user_flag_api_key": "", + "default_admin_username": "admin", + "default_admin_password": "admin", + "default_admin_email": "systems+cac@azavea.com", } @@ -75,88 +72,84 @@ # See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = secrets['secret_key'] +SECRET_KEY = secrets["secret_key"] # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = not secrets['production'] +DEBUG = not secrets["production"] # String that must be passed to post user flags for destinations or events (liked, been, etc.) -USER_FLAG_API_KEY = secrets['user_flag_api_key'] +USER_FLAG_API_KEY = secrets["user_flag_api_key"] ALLOWED_HOSTS = [ - '.gophillygo.org', - '.elb.amazonaws.com', - 'localhost', - '.ngrok.io', + ".gophillygo.org", + ".elb.amazonaws.com", + "localhost", + ".ngrok.io", ] -if secrets['production']: +if secrets["production"]: instance_metadata = get_instance_metadata() if not instance_metadata: - raise ImproperlyConfigured('Unable to access instance metadata') + raise ImproperlyConfigured("Unable to access instance metadata") # ELBs use the instance IP in the Host header and ALLOWED_HOSTS # checks against the Host header. - ALLOWED_HOSTS.append(instance_metadata['local-ipv4']) + ALLOWED_HOSTS.append(instance_metadata["local-ipv4"]) -INTERNAL_IPS = tuple(secrets['internal_ips']) +INTERNAL_IPS = tuple(secrets["internal_ips"]) # Needed in order to call collectstatic without a DB (during AMI creation) -POSTGIS_VERSION = tuple(secrets['postgis_version']) +POSTGIS_VERSION = tuple(secrets["postgis_version"]) # Application definition INSTALLED_APPS = ( - 'wpadmin', - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'django.contrib.gis', - + "wpadmin", + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "django.contrib.gis", # Third Party Apps - 'ckeditor', - 'django_extensions', - 'storages', - 'easy_thumbnails', - 'image_cropping', - + "ckeditor", + "django_extensions", + "storages", + "easy_thumbnails", + "image_cropping", # Project Apps - 'cms', - 'destinations', - 'shortlinks', + "cms", + "destinations", + "shortlinks", ) MIDDLEWARE = ( - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware' + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ) -ROOT_URLCONF = 'cac_tripplanner.urls' +ROOT_URLCONF = "cac_tripplanner.urls" -WSGI_APPLICATION = 'cac_tripplanner.wsgi.application' +WSGI_APPLICATION = "cac_tripplanner.wsgi.application" # Database # https://docs.djangoproject.com/en/1.7/ref/settings/#databases -DATABASES = { - 'default': secrets['database'] -} +DATABASES = {"default": secrets["database"]} # Image processing configuration IMAGE_CROPPING_SIZE_WARNING = True THUMBNAIL_PROCESSORS = ( - 'image_cropping.thumbnail_processors.crop_corners', + "image_cropping.thumbnail_processors.crop_corners", ) + thumbnail_settings.THUMBNAIL_PROCESSORS IMAGE_CROPPER_HELP_TEXT = """Save and return to editing this record to see an uploaded image and @@ -166,9 +159,9 @@ # Internationalization # https://docs.djangoproject.com/en/1.7/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" -TIME_ZONE = 'America/New_York' +TIME_ZONE = "America/New_York" USE_I18N = True @@ -182,81 +175,57 @@ # they will be deleted on a backwards migration from 0016 -> 0015 # NOTE: If the images placed here are to be used in production as well, they will need to be copied # to the bucket specified in AWS_STORAGE_BUCKET_NAME -DEFAULT_MEDIA_PATH = 'default_media' +DEFAULT_MEDIA_PATH = "default_media" # src directory for default media images DEFAULT_MEDIA_SRC_PATH = os.path.join(BASE_DIR, DEFAULT_MEDIA_PATH) +# Added in 3.2. This is used to create id fields for models where it's not explicitly specified in +# the model definition. This requires making an explicit choice or Django will issue warnings, so +# make our choice the same as what the default was before the requirement to make an affirmative +# choice was introduced. +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.7/howto/static-files/ -STATIC_URL = '/static/' -STATIC_ROOT = '/srv/cac' +STATIC_URL = "/static/" +STATIC_ROOT = "/srv/cac" STATICFILES_DIRS = () -MEDIA_ROOT = '/media/cac/' -MEDIA_URL = '/media/' +MEDIA_ROOT = "/media/cac/" +MEDIA_URL = "/media/" # LOGGING CONFIGURATION LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'formatters': { - 'verbose': { - 'datefmt': '%Y-%m-%d %H:%M:%S %z', - 'format': ('[%(asctime)s] [%(process)d] [%(levelname)s]' - ' %(message)s'), + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "verbose": { + "datefmt": "%Y-%m-%d %H:%M:%S %z", + "format": ("[%(asctime)s] [%(process)d] [%(levelname)s]" " %(message)s"), }, }, - 'handlers': { - 'console': { - 'class': 'logging.StreamHandler', - 'level': 'INFO', - 'formatter': 'verbose', - }, - 'logfile': { - 'level': 'DEBUG', - 'class': 'logging.FileHandler', - 'formatter': 'verbose', - 'filename': os.path.join(BASE_DIR, 'cac-tripplanner-app.log'), + "handlers": { + "console": {"class": "logging.StreamHandler", "level": "INFO", "formatter": "verbose",}, + "logfile": { + "level": "DEBUG", + "class": "logging.FileHandler", + "formatter": "verbose", + "filename": os.path.join(BASE_DIR, "cac-tripplanner-app.log"), }, }, - 'loggers': { - 'django': { - 'handlers': ['console', 'logfile'], - 'level': 'INFO', - 'propagate': True, - }, - 'ckeditor': { - 'handlers': ['console', 'logfile'], - 'level': 'DEBUG', - 'propagate': True, - }, - 'wpadmin': { - 'handlers': ['console', 'logfile'], - 'level': 'DEBUG', - 'propagate': True, - }, - 'destinations': { - 'handlers': ['console', 'logfile'], - 'level': 'DEBUG', - 'propagate': True, + "loggers": { + "django": {"handlers": ["console", "logfile"], "level": "INFO", "propagate": True,}, + "ckeditor": {"handlers": ["console", "logfile"], "level": "DEBUG", "propagate": True,}, + "wpadmin": {"handlers": ["console", "logfile"], "level": "DEBUG", "propagate": True,}, + "destinations": {"handlers": ["console", "logfile"], "level": "DEBUG", "propagate": True,}, + "cms": {"handlers": ["console", "logfile"], "level": "DEBUG", "propagate": True,}, + "shortlinks": {"handlers": ["console", "logfile"], "level": "DEBUG", "propagate": True,}, + "image_cropping.thumbnail_processors": { + "handlers": ["console", "logfile"], + "level": "DEBUG", + "propagate": True, }, - 'cms': { - 'handlers': ['console', 'logfile'], - 'level': 'DEBUG', - 'propagate': True, - }, - 'shortlinks': { - 'handlers': ['console', 'logfile'], - 'level': 'DEBUG', - 'propagate': True, - }, - 'image_cropping.thumbnail_processors': { - 'handlers': ['console', 'logfile'], - 'level': 'DEBUG', - 'propagate': True, - } - } + }, } # TEMPLATE CONFIGURATION @@ -264,110 +233,109 @@ # set renderer # https://docs.djangoproject.com/en/1.11/ref/forms/renderers/#django.forms.renderers.TemplatesSetting -FORM_RENDERER = 'django.forms.renderers.TemplatesSetting' +FORM_RENDERER = "django.forms.renderers.TemplatesSetting" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [ - os.path.normpath(os.path.join(BASE_DIR, 'templates')), - 'django/forms/templates', - 'templates', - os.path.normpath(os.path.join(django.__path__[0] + '/forms/templates')) + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [ + os.path.normpath(os.path.join(BASE_DIR, "templates")), + "django/forms/templates", + "templates", + os.path.normpath(os.path.join(django.__path__[0] + "/forms/templates")), ], - 'APP_DIRS': True, - 'OPTIONS': { - 'debug': DEBUG, - 'context_processors': [ - 'django.contrib.auth.context_processors.auth', - 'django.template.context_processors.debug', - 'django.template.context_processors.i18n', - 'django.template.context_processors.media', - 'django.template.context_processors.static', - 'django.template.context_processors.tz', - 'django.contrib.messages.context_processors.messages', - 'django.template.context_processors.request', + "APP_DIRS": True, + "OPTIONS": { + "debug": DEBUG, + "context_processors": [ + "django.contrib.auth.context_processors.auth", + "django.template.context_processors.debug", + "django.template.context_processors.i18n", + "django.template.context_processors.media", + "django.template.context_processors.static", + "django.template.context_processors.tz", + "django.contrib.messages.context_processors.messages", + "django.template.context_processors.request", ], }, }, ] -CKEDITOR_UPLOAD_PATH = 'uploads/' -CKEDITOR_IMAGE_BACKEND = 'pillow' +CKEDITOR_UPLOAD_PATH = "uploads/" +CKEDITOR_IMAGE_BACKEND = "pillow" CKEDITOR_CONFIGS = { - 'default': { - 'toolbar': [ - ["Styles", - "Format", - "Bold", - "Italic", - "Underline", - "Strike", - "SpellChecker", - "Undo", - "Redo"], + "default": { + "toolbar": [ + [ + "Styles", + "Format", + "Bold", + "Italic", + "Underline", + "Strike", + "SpellChecker", + "Undo", + "Redo", + ], ["Link", "Unlink", "Anchor"], ["Table", "HorizontalRule"], ["SpecialChar"], - ["Source"] + ["Source"], ], - 'extraPlugins': ','.join( - ['autolink', - 'autoembed', - 'embed', - 'embedsemantic', - 'autogrow']), + "extraPlugins": ",".join(["autolink", "autoembed", "embed", "embedsemantic", "autogrow"]), }, - 'teaser': { - 'toolbar': [ - ["Styles", - "Format", - "Bold", - "Italic", - "Underline", - "Strike", - "SpellChecker", - "Undo", - "Redo"], + "teaser": { + "toolbar": [ + [ + "Styles", + "Format", + "Bold", + "Italic", + "Underline", + "Strike", + "SpellChecker", + "Undo", + "Redo", + ], [], [], ["SpecialChar"], - [] + [], ], - 'extraPlugins': '', - } + "extraPlugins": "", + }, } WPADMIN = { - 'admin': { - 'title': 'Clean Air Council Content Management System', - 'menu': { - 'top': 'wpadmin.menu.menus.BasicTopMenu', - 'left': 'wpadmin.menu.menus.BasicLeftMenu' - } + "admin": { + "title": "Clean Air Council Content Management System", + "menu": { + "top": "wpadmin.menu.menus.BasicTopMenu", + "left": "wpadmin.menu.menus.BasicLeftMenu", + }, } } # FACEBOOK CONFIGURATION -FB_APP_ID = secrets['fb_app_id'] +FB_APP_ID = secrets["fb_app_id"] # OTP CONFIGURATION -OTP_URL = secrets['otp_url'] -ROUTING_URL = OTP_URL.format(router='default') + 'plan' -ISOCHRONE_URL = OTP_URL.format(router='default') + 'isochrone' +OTP_URL = secrets["otp_url"] +ROUTING_URL = OTP_URL.format(router="default") + "plan" +ISOCHRONE_URL = OTP_URL.format(router="default") + "isochrone" # Settings for S3 storage # No need to specify AWS access and secret keys -- they are pulled from # the instance metadata by boto. -if secrets['use_s3_storage']: - DEFAULT_FILE_STORAGE = 'cac_tripplanner.custom_storages.PublicS3BotoStorage' - AWS_STORAGE_BUCKET_NAME = secrets['aws_storage_bucket_name'] +if secrets["use_s3_storage"]: + DEFAULT_FILE_STORAGE = "cac_tripplanner.custom_storages.PublicS3BotoStorage" + AWS_STORAGE_BUCKET_NAME = secrets["aws_storage_bucket_name"] # Default user -DEFAULT_ADMIN_USERNAME = secrets['default_admin_username'] -DEFAULT_ADMIN_PASSWORD = secrets['default_admin_password'] -DEFAULT_ADMIN_EMAIL = secrets['default_admin_email'] +DEFAULT_ADMIN_USERNAME = secrets["default_admin_username"] +DEFAULT_ADMIN_PASSWORD = secrets["default_admin_password"] +DEFAULT_ADMIN_EMAIL = secrets["default_admin_email"] # Application settings # diff --git a/python/cac_tripplanner/cac_tripplanner/urls.py b/python/cac_tripplanner/cac_tripplanner/urls.py index 7647b8a50..9a67d3176 100644 --- a/python/cac_tripplanner/cac_tripplanner/urls.py +++ b/python/cac_tripplanner/cac_tripplanner/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls import url +from django.conf.urls import re_path from django.urls import include from django.views.generic import RedirectView from django.contrib.gis import admin @@ -12,55 +12,47 @@ urlpatterns = [ # Home view, which is also the directions and explore views - url(r'^$', dest_views.home, name='home'), - url(r'^explore$', dest_views.explore, name='explore'), - + re_path(r"^$", dest_views.home, name="home"), + re_path(r"^explore$", dest_views.explore, name="explore"), # App manifest and service worker for PWA app - url('^manifest.json$', dest_views.manifest), - url('^service-worker.js$', dest_views.service_worker), - + re_path("^manifest.json$", dest_views.manifest), + re_path("^service-worker.js$", dest_views.service_worker), # Privacy policy and ToS - url(r'^privacy_policy$', dest_views.privacy_policy, name='privacy_policy'), - url(r'^terms_of_service$', dest_views.terms_of_service, name='terms_of_service'), - + re_path(r"^privacy_policy$", dest_views.privacy_policy, name="privacy_policy"), + re_path(r"^terms_of_service$", dest_views.terms_of_service, name="terms_of_service"), # User destination flags - url(r'^api/user_flag/', dest_views.UserFlagView.as_view()), - + re_path(r"^api/user_flag/", dest_views.UserFlagView.as_view()), # Map - url(r'^api/destinations/search$', dest_views.SearchDestinations.as_view(), - name='api_destinations_search'), - url(r'^map/reachable$', dest_views.FindReachableDestinations.as_view(), name='reachable'), - + re_path( + r"^api/destinations/search$", + dest_views.SearchDestinations.as_view(), + name="api_destinations_search", + ), + re_path(r"^map/reachable$", dest_views.FindReachableDestinations.as_view(), name="reachable"), # Handle pre-redesign URLs by redirecting - url(r'^(?:map/)?directions/', RedirectView.as_view(pattern_name='home', query_string=True, - permanent=True)), - + re_path( + r"^(?:map/)?directions/", + RedirectView.as_view(pattern_name="home", query_string=True, permanent=True), + ), # Places - url(r'^place/(?P[\d-]+)/$', dest_views.place_detail, name='place-detail'), - + re_path(r"^place/(?P[\d-]+)/$", dest_views.place_detail, name="place-detail"), # Events - url(r'^event/(?P[\d-]+)/$', dest_views.event_detail, name='event-detail'), - + re_path(r"^event/(?P[\d-]+)/$", dest_views.event_detail, name="event-detail"), # Tours - url(r'^tour/(?P[\d-]+)/$', dest_views.tour_detail, name='tour-detail'), - + re_path(r"^tour/(?P[\d-]+)/$", dest_views.tour_detail, name="tour-detail"), # About (no more FAQ) - url(r'^(?Pabout)/$', cms_views.about_faq, name='about'), - + re_path(r"^(?Pabout)/$", cms_views.about_faq, name="about"), # All Published Articles - url(r'^api/articles$', cms_views.AllArticles.as_view(), name='api_articles'), - + re_path(r"^api/articles$", cms_views.AllArticles.as_view(), name="api_articles"), # Community Profiles - url(r'^learn/$', cms_views.learn_list, name='learn-list'), - url(r'^learn/(?P[\w-]+)/$', cms_views.learn_detail, name='learn-detail'), - + re_path(r"^learn/$", cms_views.learn_list, name="learn-list"), + re_path(r"^learn/(?P[\w-]+)/$", cms_views.learn_detail, name="learn-detail"), # Link Shortening - url(r'^link/', include('shortlinks.urls', namespace='shortlinks')), - - url(r'^admin/', admin.site.urls), + re_path(r"^link/", include("shortlinks.urls", namespace="shortlinks")), + re_path(r"^admin/", admin.site.urls), ] if settings.DEBUG: urlpatterns += [ - url(r'^static/(?P.*)$', staticviews.serve), + re_path(r"^static/(?P.*)$", staticviews.serve), ] diff --git a/python/cac_tripplanner/cms/__init__.py b/python/cac_tripplanner/cms/__init__.py index 2957bf076..e69de29bb 100644 --- a/python/cac_tripplanner/cms/__init__.py +++ b/python/cac_tripplanner/cms/__init__.py @@ -1 +0,0 @@ -default_app_config = 'cms.apps.CMSConfig' diff --git a/python/cac_tripplanner/cms/tests.py b/python/cac_tripplanner/cms/tests.py index 56efbee0d..04139a7fc 100644 --- a/python/cac_tripplanner/cms/tests.py +++ b/python/cac_tripplanner/cms/tests.py @@ -11,43 +11,47 @@ class ArticleTests(TestCase): def setUp(self): - user = User.objects.create_user(username='test-user') - test_image = File(open('default_media/square/BartramsGarden.jpg')) - - common_args = dict( - teaser='None', - content='None', - author=user, - narrow_image=test_image, - wide_image=test_image - ) - - publish_date = now() - timedelta(hours=1) - self.client = Client() - - self.unpublished_comm = Article.objects.create( - content_type=Article.ArticleTypes.community_profile, - title='unpublished-comm', - slug='unpublished-comm', - **common_args) - self.unpublished_tips = Article.objects.create( - content_type=Article.ArticleTypes.tips_and_tricks, - title='unpublished-tips', - slug='unpublished-tips', - **common_args) - self.published_comm = Article.objects.create( - content_type=Article.ArticleTypes.community_profile, - publish_date=publish_date, - title='published-comm', - slug='published-comm', - **common_args) - self.published_tips = Article.objects.create( - content_type=Article.ArticleTypes.tips_and_tricks, - publish_date=publish_date, - title='published-tips', - slug='published-tips', - **common_args) + user = User.objects.create_user(username="test-user") + with open("default_media/square/BartramsGarden.jpg") as image_file: + test_image = File(image_file) + + common_args = dict( + teaser="None", + content="None", + author=user, + narrow_image=test_image, + wide_image=test_image, + ) + + publish_date = now() - timedelta(hours=1) + + self.unpublished_comm = Article.objects.create( + content_type=Article.ArticleTypes.community_profile, + title="unpublished-comm", + slug="unpublished-comm", + **common_args + ) + self.unpublished_tips = Article.objects.create( + content_type=Article.ArticleTypes.tips_and_tricks, + title="unpublished-tips", + slug="unpublished-tips", + **common_args + ) + self.published_comm = Article.objects.create( + content_type=Article.ArticleTypes.community_profile, + publish_date=publish_date, + title="published-comm", + slug="published-comm", + **common_args + ) + self.published_tips = Article.objects.create( + content_type=Article.ArticleTypes.tips_and_tricks, + publish_date=publish_date, + title="published-tips", + slug="published-tips", + **common_args + ) def test_home_view(self): """Verify that home view includes one article""" @@ -55,9 +59,9 @@ def test_home_view(self): # Delete second published article so random always returns the same item self.published_tips.delete() - url = reverse('home') + url = reverse("home") response = self.client.get(url) - self.assertContains(response, 'Places we love', status_code=200) + self.assertContains(response, "Places we love", status_code=200) self.assertContains(response, self.published_comm.title, status_code=200) def test_community_profile_manager(self): @@ -93,19 +97,17 @@ def test_article_manager(self): def test_learn_detail_view(self): """Test that learn detail view works""" - url = reverse('learn-detail', - kwargs={'slug': self.published_comm.slug}) + url = reverse("learn-detail", kwargs={"slug": self.published_comm.slug}) response = self.client.get(url) - self.assertContains(response, 'published-comm', status_code=200) + self.assertContains(response, "published-comm", status_code=200) - url = reverse('learn-detail', - kwargs={'slug': self.unpublished_comm.slug}) + url = reverse("learn-detail", kwargs={"slug": self.unpublished_comm.slug}) response_404 = self.client.get(url) self.assertEqual(response_404.status_code, 404) def test_learn_list_view(self): """Test that learn list view works""" - url = reverse('learn-list') + url = reverse("learn-list") response = self.client.get(url) self.assertContains(response, self.published_comm.title, status_code=200) diff --git a/python/cac_tripplanner/destinations/__init__.py b/python/cac_tripplanner/destinations/__init__.py index ea21cb168..e69de29bb 100644 --- a/python/cac_tripplanner/destinations/__init__.py +++ b/python/cac_tripplanner/destinations/__init__.py @@ -1 +0,0 @@ -default_app_config = 'destinations.apps.DestinationsConfig' diff --git a/python/cac_tripplanner/destinations/admin.py b/python/cac_tripplanner/destinations/admin.py index ba9348d12..1f5827798 100644 --- a/python/cac_tripplanner/destinations/admin.py +++ b/python/cac_tripplanner/destinations/admin.py @@ -3,7 +3,6 @@ from django.conf import settings from django.contrib import admin, gis -from django import forms from image_cropping import ImageCroppingMixin diff --git a/python/cac_tripplanner/destinations/tests.py b/python/cac_tripplanner/destinations/tests.py index 3198f92ac..779be5305 100644 --- a/python/cac_tripplanner/destinations/tests.py +++ b/python/cac_tripplanner/destinations/tests.py @@ -15,29 +15,32 @@ def setUp(self): # Clear DB of objects created by migrations Event.objects.all().delete() - test_image = File(open('default_media/square/BartramsGarden.jpg')) + with open("default_media/square/BartramsGarden.jpg") as image_file: + test_image = File(image_file) - self.now = now() + self.now = now() - common_args = dict( - description='Sample event for tests', - image=test_image, - wide_image=test_image - ) - - self.client = Client() + common_args = dict( + description="Sample event for tests", image=test_image, wide_image=test_image + ) - self.event_1 = Event.objects.create(name='Current Event', - published=True, - start_date=self.now, - end_date=self.now + timedelta(days=1), - **common_args) + self.client = Client() - self.event_2 = Event.objects.create(name='Unpublished Past Event', - published=False, - start_date=self.now - timedelta(days=7), - end_date=self.now - timedelta(days=2), - **common_args) + self.event_1 = Event.objects.create( + name="Current Event", + published=True, + start_date=self.now, + end_date=self.now + timedelta(days=1), + **common_args + ) + + self.event_2 = Event.objects.create( + name="Unpublished Past Event", + published=False, + start_date=self.now - timedelta(days=7), + end_date=self.now - timedelta(days=2), + **common_args + ) def test_event_manager_published(self): self.assertEqual(Event.objects.published().count(), 1) @@ -47,27 +50,25 @@ def test_event_manager_current(self): def test_event_detail_view(self): """Test that event detail view works""" - url = reverse('event-detail', - kwargs={'pk': self.event_1.pk}) + url = reverse("event-detail", kwargs={"pk": self.event_1.pk}) response = self.client.get(url) - self.assertContains(response, 'Current Event', status_code=200) + self.assertContains(response, "Current Event", status_code=200) # can also view detail for unpublished event - url = reverse('event-detail', - kwargs={'pk': self.event_2.pk}) + url = reverse("event-detail", kwargs={"pk": self.event_2.pk}) response = self.client.get(url) - self.assertContains(response, 'Unpublished Past Event', status_code=200) + self.assertContains(response, "Unpublished Past Event", status_code=200) def test_event_search(self): """Test that event shows in search results""" - url = reverse('api_destinations_search') + url = reverse("api_destinations_search") response = self.client.get(url) - self.assertContains(response, 'events', status_code=200) + self.assertContains(response, "events", status_code=200) json_response = json.loads(response.content) - self.assertEqual(len(json_response['events']), 1) - event = json_response['events'][0] - self.assertEqual(event['name'], 'Current Event') - self.assertIn('Events', event['categories']) + self.assertEqual(len(json_response["events"]), 1) + event = json_response["events"][0] + self.assertEqual(event["name"], "Current Event") + self.assertIn("Events", event["categories"]) class EventMultiDestinationTests(TestCase): @@ -77,46 +78,45 @@ def setUp(self): Event.objects.all().delete() Destination.objects.all().delete() - test_image = File(open('default_media/square/BartramsGarden.jpg')) + with open("default_media/square/BartramsGarden.jpg") as image_file: + test_image = File(image_file) - self.now = now() + self.now = now() - dest_args = dict( - description='Sample place for tests', - image=test_image, - wide_image=test_image, - point=Point(0, 0) - ) - - event_args = dict( - description='Sample event for tests', - image=test_image, - wide_image=test_image - ) + dest_args = dict( + description="Sample place for tests", + image=test_image, + wide_image=test_image, + point=Point(0, 0), + ) - self.client = Client() + event_args = dict( + description="Sample event for tests", image=test_image, wide_image=test_image + ) - self.place_1 = Destination.objects.create( - name='place_one', - published=True, - **dest_args) + self.client = Client() - self.place_2 = Destination.objects.create( - name='place_two', - published=False, - **dest_args) + self.place_1 = Destination.objects.create(name="place_one", published=True, **dest_args) - self.event_1 = Event.objects.create(name='single_day_event', - published=True, - start_date=self.now, - end_date=self.now + timedelta(days=1), - **event_args) + self.place_2 = Destination.objects.create( + name="place_two", published=False, **dest_args + ) - self.event_2 = Event.objects.create(name='multi_day_event', - published=True, - start_date=self.now - timedelta(days=7), - end_date=self.now + timedelta(days=2), - **event_args) + self.event_1 = Event.objects.create( + name="single_day_event", + published=True, + start_date=self.now, + end_date=self.now + timedelta(days=1), + **event_args + ) + + self.event_2 = Event.objects.create( + name="multi_day_event", + published=True, + start_date=self.now - timedelta(days=7), + end_date=self.now + timedelta(days=2), + **event_args + ) self.event_1.event_destinations.add( EventDestination.objects.create( @@ -124,8 +124,9 @@ def setUp(self): related_event=self.event_1, order=2, start_date=self.now + timedelta(hours=8), - end_date=self.now + timedelta(hours=14) - )) + end_date=self.now + timedelta(hours=14), + ) + ) self.event_1.event_destinations.add( EventDestination.objects.create( @@ -133,8 +134,9 @@ def setUp(self): related_event=self.event_1, order=1, start_date=self.now + timedelta(hours=14), - end_date=self.now + timedelta(hours=18) - )) + end_date=self.now + timedelta(hours=18), + ) + ) self.event_1.save() @@ -144,8 +146,9 @@ def setUp(self): related_event=self.event_2, order=1, start_date=self.now, - end_date=self.now + timedelta(days=1) - )) + end_date=self.now + timedelta(days=1), + ) + ) self.event_2.event_destinations.add( EventDestination.objects.create( @@ -153,8 +156,9 @@ def setUp(self): related_event=self.event_2, order=2, start_date=self.now + timedelta(days=1), - end_date=self.now + timedelta(days=2) - )) + end_date=self.now + timedelta(days=2), + ) + ) self.event_2.save() @@ -166,15 +170,13 @@ def test_event_manager_current(self): def test_event_detail_view(self): """Test that event detail view works""" - url = reverse('event-detail', - kwargs={'pk': self.event_1.pk}) + url = reverse("event-detail", kwargs={"pk": self.event_1.pk}) response = self.client.get(url) - self.assertContains(response, 'single_day_event', status_code=200) + self.assertContains(response, "single_day_event", status_code=200) - url = reverse('event-detail', - kwargs={'pk': self.event_2.pk}) + url = reverse("event-detail", kwargs={"pk": self.event_2.pk}) response = self.client.get(url) - self.assertContains(response, 'multi_day_event', status_code=200) + self.assertContains(response, "multi_day_event", status_code=200) def test_event_destination_order(self): self.assertEqual(self.event_1.event_destinations.count(), 2) @@ -183,8 +185,7 @@ def test_event_destination_order(self): # second place should have first order, and be returned first event_1_first_dest = self.event_1.event_destinations.first() self.assertEqual(event_1_first_dest.order, 1) - self.assertEqual(event_1_first_dest.destination.id, - self.place_2.id) + self.assertEqual(event_1_first_dest.destination.id, self.place_2.id) # other place has second order self.assertEqual(self.event_1.event_destinations.all()[1].order, 2) @@ -193,25 +194,25 @@ def test_event_destination_order(self): def test_event_search(self): """Test that events show in search results""" - url = reverse('api_destinations_search') + url = reverse("api_destinations_search") response = self.client.get(url) - self.assertContains(response, 'events', status_code=200) + self.assertContains(response, "events", status_code=200) json_response = json.loads(response.content) - self.assertEqual(len(json_response['events']), 2) - first_event = json_response['events'][0] + self.assertEqual(len(json_response["events"]), 2) + first_event = json_response["events"][0] # multi day event started earlier and should be listed first - self.assertEqual(first_event['name'], 'multi_day_event') - self.assertIn('Events', first_event['categories']) - self.assertEqual(len(first_event['destinations']), 2) - self.assertEqual(first_event['destinations'][0]['name'], 'place_one') - self.assertEqual(first_event['destinations'][1]['name'], 'place_two') + self.assertEqual(first_event["name"], "multi_day_event") + self.assertIn("Events", first_event["categories"]) + self.assertEqual(len(first_event["destinations"]), 2) + self.assertEqual(first_event["destinations"][0]["name"], "place_one") + self.assertEqual(first_event["destinations"][1]["name"], "place_two") # single day event orders destinations differently - second_event = json_response['events'][1] - self.assertEqual(second_event['name'], 'single_day_event') - self.assertEqual(len(second_event['destinations']), 2) - self.assertEqual(second_event['destinations'][0]['name'], 'place_two') - self.assertEqual(second_event['destinations'][1]['name'], 'place_one') + second_event = json_response["events"][1] + self.assertEqual(second_event["name"], "single_day_event") + self.assertEqual(len(second_event["destinations"]), 2) + self.assertEqual(second_event["destinations"][0]["name"], "place_two") + self.assertEqual(second_event["destinations"][1]["name"], "place_one") class DestinationTests(TestCase): @@ -220,55 +221,51 @@ def setUp(self): # Clear DB of objects created by migrations Destination.objects.all().delete() - test_image = File(open('default_media/square/BartramsGarden.jpg')) + with open("default_media/square/BartramsGarden.jpg") as image_file: + test_image = File(image_file) - common_args = dict( - description='Sample place for tests', - image=test_image, - wide_image=test_image, - point=Point(0, 0) - ) + common_args = dict( + description="Sample place for tests", + image=test_image, + wide_image=test_image, + point=Point(0, 0), + ) - self.client = Client() + self.client = Client() - self.place_1 = Destination.objects.create( - name='place_one', - published=True, - **common_args) + self.place_1 = Destination.objects.create( + name="place_one", published=True, **common_args + ) - self.place_2 = Destination.objects.create( - name='place_two', - published=True, - **common_args) + self.place_2 = Destination.objects.create( + name="place_two", published=True, **common_args + ) - self.place_3 = Destination.objects.create( - name='place_three', - published=False, - **common_args) + self.place_3 = Destination.objects.create( + name="place_three", published=False, **common_args + ) def test_destination_manager_published(self): self.assertEqual(Destination.objects.published().count(), 2) def test_place_detail_view(self): """Test that place detail view works""" - url = reverse('place-detail', - kwargs={'pk': self.place_1.pk}) + url = reverse("place-detail", kwargs={"pk": self.place_1.pk}) response = self.client.get(url) - self.assertContains(response, 'place_one', status_code=200) + self.assertContains(response, "place_one", status_code=200) # unpublished place should also be viewable - url = reverse('place-detail', - kwargs={'pk': self.place_3.pk}) + url = reverse("place-detail", kwargs={"pk": self.place_3.pk}) response = self.client.get(url) self.assertEqual(response.status_code, 200) def test_destination_search(self): """Test that destinations show in search results""" - url = reverse('api_destinations_search') + '?text=place' + url = reverse("api_destinations_search") + "?text=place" response = self.client.get(url) - self.assertContains(response, 'destinations', status_code=200) + self.assertContains(response, "destinations", status_code=200) json_response = json.loads(response.content) - self.assertEqual(len(json_response['destinations']), 2) + self.assertEqual(len(json_response["destinations"]), 2) class TourTests(TestCase): @@ -278,70 +275,56 @@ def setUp(self): Tour.objects.all().delete() Destination.objects.all().delete() - test_image = File(open('default_media/square/BartramsGarden.jpg')) + self.client = Client() - self.now = now() + with open("default_media/square/BartramsGarden.jpg") as image_file: + test_image = File(image_file) - dest_args = dict( - description='Sample place for tests', - image=test_image, - wide_image=test_image, - point=Point(0, 0) - ) + self.now = now() - tour_args = dict( - description='Sample tour for tests' - ) + dest_args = dict( + description="Sample place for tests", + image=test_image, + wide_image=test_image, + point=Point(0, 0), + ) - self.client = Client() - - self.place_1 = Destination.objects.create( - name='place_one', - published=True, - **dest_args) + self.place_1 = Destination.objects.create(name="place_one", published=True, **dest_args) - self.place_2 = Destination.objects.create( - name='place_two', - published=False, - **dest_args) + self.place_2 = Destination.objects.create( + name="place_two", published=False, **dest_args + ) - self.tour_1 = Tour.objects.create(name='tour_one', - published=True, - **tour_args) + tour_args = dict(description="Sample tour for tests") + self.tour_1 = Tour.objects.create(name="tour_one", published=True, **tour_args) - self.tour_2 = Tour.objects.create(name='tour_two', - published=False, - **tour_args) + self.tour_2 = Tour.objects.create(name="tour_two", published=False, **tour_args) self.tour_1.tour_destinations.add( TourDestination.objects.create( - destination=self.place_1, - related_tour=self.tour_1, - order=2 - )) + destination=self.place_1, related_tour=self.tour_1, order=2 + ) + ) self.tour_1.tour_destinations.add( TourDestination.objects.create( - destination=self.place_2, - related_tour=self.tour_1, - order=1 - )) + destination=self.place_2, related_tour=self.tour_1, order=1 + ) + ) self.tour_1.save() self.tour_2.tour_destinations.add( TourDestination.objects.create( - destination=self.place_1, - related_tour=self.tour_2, - order=1 - )) + destination=self.place_1, related_tour=self.tour_2, order=1 + ) + ) self.tour_2.tour_destinations.add( TourDestination.objects.create( - destination=self.place_2, - related_tour=self.tour_2, - order=2 - )) + destination=self.place_2, related_tour=self.tour_2, order=2 + ) + ) self.tour_2.save() @@ -351,24 +334,22 @@ def test_tour_manager_published(self): def test_tour_detail_view(self): """Test that tour detail view works""" - url = reverse('tour-detail', - kwargs={'pk': self.tour_1.pk}) + url = reverse("tour-detail", kwargs={"pk": self.tour_1.pk}) response = self.client.get(url) - self.assertContains(response, 'tour_one', status_code=200) + self.assertContains(response, "tour_one", status_code=200) # unpublished tour detail should also be available - url = reverse('tour-detail', - kwargs={'pk': self.tour_2.pk}) + url = reverse("tour-detail", kwargs={"pk": self.tour_2.pk}) response = self.client.get(url) self.assertEqual(response.status_code, 200) def test_tour_search(self): """Test that tour shows in search results""" - url = reverse('api_destinations_search') + url = reverse("api_destinations_search") response = self.client.get(url) - self.assertContains(response, 'tours', status_code=200) + self.assertContains(response, "tours", status_code=200) json_response = json.loads(response.content) - self.assertEqual(len(json_response['tours']), 1) + self.assertEqual(len(json_response["tours"]), 1) def test_tour_destination_order(self): self.assertEqual(self.tour_1.tour_destinations.count(), 2) @@ -377,8 +358,7 @@ def test_tour_destination_order(self): # second place should have first order, and be returned first tour_1_first_dest = self.tour_1.tour_destinations.first() self.assertEqual(tour_1_first_dest.order, 1) - self.assertEqual(tour_1_first_dest.destination.id, - self.place_2.id) + self.assertEqual(tour_1_first_dest.destination.id, self.place_2.id) # other place has second order self.assertEqual(self.tour_1.tour_destinations.all()[1].order, 2) diff --git a/python/cac_tripplanner/requirements.txt b/python/cac_tripplanner/requirements.txt index 2b7dd0db8..1b9732adb 100644 --- a/python/cac_tripplanner/requirements.txt +++ b/python/cac_tripplanner/requirements.txt @@ -1,16 +1,16 @@ base58==2.0.1 boto3==1.15.9 -Django==2.2.16 +Django==3.2.13 django-ckeditor==6.0.0 django-image-cropping==1.5.0 -django-extensions==3.0.9 +django-extensions==3.1.5 django-storages==1.10.1 -easy-thumbnails==2.7 +easy-thumbnails==2.8.1 gunicorn==20.0.4 Pillow==7.2.0 psycopg2-binary==2.8.6 pytz==2020.1 PyYAML==5.3.1 requests==2.24.0 -git+https://github.com/azavea/django-wpadmin@v2.2#egg=django-wpadmin +git+https://github.com/azavea/django-wpadmin@v3.2#egg=django-wpadmin virtualenv==20.0.31 diff --git a/python/cac_tripplanner/shortlinks/test/urls.py b/python/cac_tripplanner/shortlinks/test/urls.py index 1a0779b3c..3b14ef2df 100644 --- a/python/cac_tripplanner/shortlinks/test/urls.py +++ b/python/cac_tripplanner/shortlinks/test/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls import url +from django.conf.urls import re_path from django.urls import include, path from shortlinks.test.views import stub_view @@ -6,5 +6,5 @@ urlpatterns = [ path('link/', include('shortlinks.urls')), - url(r'^$', stub_view, name='test-home'), + re_path(r'^$', stub_view, name='test-home'), ] diff --git a/python/cac_tripplanner/shortlinks/urls.py b/python/cac_tripplanner/shortlinks/urls.py index a46721cdf..ce4d9d0bc 100644 --- a/python/cac_tripplanner/shortlinks/urls.py +++ b/python/cac_tripplanner/shortlinks/urls.py @@ -1,13 +1,15 @@ -from django.conf.urls import url +from django.conf.urls import re_path from django.views.decorators.csrf import csrf_exempt from .views import ShortenedLinkRedirectView, ShortenedLinkCreateView -app_name = 'shortlinks' +app_name = "shortlinks" urlpatterns = [ - url(r'^(?P[1-9A-Za-z]{15,30})$', ShortenedLinkRedirectView.as_view(), - name='dereference-shortened'), - url(r'^shorten/$', csrf_exempt(ShortenedLinkCreateView.as_view()), - name='shorten-link') + re_path( + r"^(?P[1-9A-Za-z]{15,30})$", + ShortenedLinkRedirectView.as_view(), + name="dereference-shortened", + ), + re_path(r"^shorten/$", csrf_exempt(ShortenedLinkCreateView.as_view()), name="shorten-link"), ] diff --git a/python/cac_tripplanner/templates/base.html b/python/cac_tripplanner/templates/base.html index 87a599c36..d6d8e9d7d 100644 --- a/python/cac_tripplanner/templates/base.html +++ b/python/cac_tripplanner/templates/base.html @@ -1,5 +1,5 @@ -{% load staticfiles %} +{% load static %} diff --git a/python/cac_tripplanner/templates/event-detail.html b/python/cac_tripplanner/templates/event-detail.html index 71b484743..6dee23d09 100644 --- a/python/cac_tripplanner/templates/event-detail.html +++ b/python/cac_tripplanner/templates/event-detail.html @@ -1,6 +1,6 @@ {% extends "base.html" %} {% load cropping %} -{% load staticfiles %} +{% load static %} {% block pagetitle %} {% block title %}GoPhillyGo | {{ event.name }}{% endblock %} diff --git a/python/cac_tripplanner/templates/home.html b/python/cac_tripplanner/templates/home.html index ae507183d..20add40bf 100644 --- a/python/cac_tripplanner/templates/home.html +++ b/python/cac_tripplanner/templates/home.html @@ -1,6 +1,6 @@ {% extends "base.html" %} {% load cropping %} -{% load staticfiles %} +{% load static %} {% load destination_extras %} {% load tz %} {% block content %} diff --git a/python/cac_tripplanner/templates/learn-detail.html b/python/cac_tripplanner/templates/learn-detail.html index b71de2b3f..409d7947d 100644 --- a/python/cac_tripplanner/templates/learn-detail.html +++ b/python/cac_tripplanner/templates/learn-detail.html @@ -1,6 +1,6 @@ {% extends "base.html" %} {% load cropping %} -{% load staticfiles %} +{% load static %} {% block pagetitle %} {% block title %}GoPhillyGo | {{ article.title }}{% endblock %} diff --git a/python/cac_tripplanner/templates/learn-list.html b/python/cac_tripplanner/templates/learn-list.html index 50663073f..d19d928f7 100644 --- a/python/cac_tripplanner/templates/learn-list.html +++ b/python/cac_tripplanner/templates/learn-list.html @@ -1,5 +1,5 @@ {% extends "base.html" %} -{% load staticfiles %} +{% load static %} {% block content %} {% include "partials/header.html" %}
diff --git a/python/cac_tripplanner/templates/place-detail.html b/python/cac_tripplanner/templates/place-detail.html index 9a86f6826..17a05a9d0 100644 --- a/python/cac_tripplanner/templates/place-detail.html +++ b/python/cac_tripplanner/templates/place-detail.html @@ -1,6 +1,6 @@ {% extends "base.html" %} {% load cropping %} -{% load staticfiles %} +{% load static %} {% block pagetitle %} {% block title %}GoPhillyGo | {{ destination.name }}{% endblock %} diff --git a/python/cac_tripplanner/templates/privacy-policy.html b/python/cac_tripplanner/templates/privacy-policy.html index c6d42edc4..33b177631 100644 --- a/python/cac_tripplanner/templates/privacy-policy.html +++ b/python/cac_tripplanner/templates/privacy-policy.html @@ -1,6 +1,6 @@ {% extends "base.html" %} {% load cropping %} -{% load staticfiles %} +{% load static %} {% block pagetitle %} {% block title %}GoPhillyGo | Privacy Policy{% endblock %} diff --git a/python/cac_tripplanner/templates/terms-of-service.html b/python/cac_tripplanner/templates/terms-of-service.html index 700f31e96..d2bd449b0 100644 --- a/python/cac_tripplanner/templates/terms-of-service.html +++ b/python/cac_tripplanner/templates/terms-of-service.html @@ -1,6 +1,6 @@ {% extends "base.html" %} {% load cropping %} -{% load staticfiles %} +{% load static %} {% block pagetitle %} {% block title %}GoPhillyGo | Terms of Service{% endblock %} diff --git a/python/cac_tripplanner/templates/tour-detail.html b/python/cac_tripplanner/templates/tour-detail.html index c7652824b..86bdf60fd 100644 --- a/python/cac_tripplanner/templates/tour-detail.html +++ b/python/cac_tripplanner/templates/tour-detail.html @@ -1,6 +1,6 @@ {% extends "base.html" %} {% load cropping %} -{% load staticfiles %} +{% load static %} {% block pagetitle %} {% block title %}GoPhillyGo | {{ tour.name }}{% endblock %} diff --git a/python/pyproject.toml b/python/pyproject.toml new file mode 100644 index 000000000..5ce78645b --- /dev/null +++ b/python/pyproject.toml @@ -0,0 +1,2 @@ +[tool.black] +line-length = 100 diff --git a/python/setup.cfg b/python/setup.cfg index 13bc986ff..3ff6af6ed 100644 --- a/python/setup.cfg +++ b/python/setup.cfg @@ -1,4 +1,4 @@ [flake8] -ignore = W504 +ignore = W504,E231 max-line-length = 100 exclude = tests/*