Merge branch 'dj3'

This commit is contained in:
Yohan Boniface 2021-08-06 11:12:12 +02:00
commit e6b02724eb
14 changed files with 92 additions and 74 deletions

View file

@ -1,21 +1,22 @@
sudo: false
os: linux
language: python
dist: xenial
dist: focal
python:
- "3.6"
- "3.7"
- "3.8"
- "3.9"
services:
- postgresql
- postgresql
addons:
postgresql: "9.6"
apt:
packages:
- libgdal-dev
- postgresql-9.6-postgis-2.4
- postgresql-12-postgis-3
env:
- UMAP_SETTINGS=umap/tests/settings.py
global:
- PGPORT=5432
- UMAP_SETTINGS=umap/tests/settings.py
install:
- pip install .
- pip install -r requirements-dev.txt
@ -23,7 +24,7 @@ script: make test
notifications:
irc:
channels:
- "irc.freenode.net#umap"
- "irc.libera.chat#umap"
on_success: change
on_failure: always
email: false

View file

@ -1,4 +1,4 @@
factory-boy==2.12.0
mkdocs==1.1
pytest==5.4.1
pytest-django==3.8.0
factory-boy==3.2.0
mkdocs==1.1.2
pytest==6.2.4
pytest-django==4.3.0

View file

@ -1,8 +1,8 @@
Django==2.2.17
Django==3.2.3
django-agnocomplete==1.0.0
django-compressor==2.4
Pillow==8.0.1
psycopg2==2.8.4
requests==2.23.0
social-auth-core==3.3.2
social-auth-app-django==3.1.0
django-compressor==2.4.1
Pillow==8.2.0
psycopg2==2.8.6
requests==2.25.1
social-auth-core==4.1.0
social-auth-app-django==4.0.0

View file

@ -1,6 +1,6 @@
import json
from django.utils import six
import six
from django.db import models
from django.utils.encoding import smart_text

View file

@ -1,7 +1,7 @@
from django import forms
from django.contrib.gis.geos import Point
from django.contrib.auth import get_user_model
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.template.defaultfilters import slugify
from django.conf import settings
from django.forms.utils import ErrorList

View file

@ -1,7 +1,7 @@
from django.conf import settings
from django.core.exceptions import MiddlewareNotUsed
from django.http import HttpResponseForbidden
from django.utils.translation import ugettext as _
from django.utils.translation import gettext as _
def readonly_middleware(get_response):

View file

@ -4,7 +4,7 @@ import time
from django.contrib.gis.db import models
from django.conf import settings
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from django.core.signing import Signer
from django.template.defaultfilters import slugify
from django.core.files.base import File

View file

@ -1,6 +1,6 @@
import imp
import os
import sys
import types
from django.utils.termcolors import colorize
@ -22,7 +22,7 @@ if not path:
print(colorize(msg, fg='red'))
sys.exit(1)
d = imp.new_module('config')
d = types.ModuleType('config')
d.__file__ = path
try:
with open(path) as config_file:

View file

@ -1,6 +1,5 @@
"""Base settings shared by all environments"""
# Import global settings to make it easier to extend settings.
from django.conf.global_settings import * # pylint: disable=W0614,W0401
from django.template.defaultfilters import slugify
from django.conf.locale import LANG_INFO
@ -130,8 +129,10 @@ STATIC_ROOT = os.path.join('static')
MEDIA_ROOT = os.path.join('uploads')
STATICFILES_FINDERS = [
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'compressor.finders.CompressorFinder',
] + STATICFILES_FINDERS
]
# =============================================================================
# Templates

View file

@ -10,14 +10,14 @@ from umap.models import DataLayer, Licence, Map, TileLayer
User = get_user_model()
class LicenceFactory(factory.DjangoModelFactory):
class LicenceFactory(factory.django.DjangoModelFactory):
name = "WTFPL"
class Meta:
model = Licence
class TileLayerFactory(factory.DjangoModelFactory):
class TileLayerFactory(factory.django.DjangoModelFactory):
name = "Test zoom layer"
url_template = "http://{s}.test.org/{z}/{x}/{y}.png"
attribution = "Test layer attribution"
@ -26,7 +26,7 @@ class TileLayerFactory(factory.DjangoModelFactory):
model = TileLayer
class UserFactory(factory.DjangoModelFactory):
class UserFactory(factory.django.DjangoModelFactory):
username = 'Joe'
email = factory.LazyAttribute(
lambda a: '{0}@example.com'.format(a.username).lower())
@ -36,7 +36,7 @@ class UserFactory(factory.DjangoModelFactory):
model = User
class MapFactory(factory.DjangoModelFactory):
class MapFactory(factory.django.DjangoModelFactory):
name = "test map"
slug = "test-map"
center = DEFAULT_CENTER
@ -76,7 +76,7 @@ class MapFactory(factory.DjangoModelFactory):
model = Map
class DataLayerFactory(factory.DjangoModelFactory):
class DataLayerFactory(factory.django.DjangoModelFactory):
map = factory.SubFactory(MapFactory)
name = "test datalayer"
description = "test description"

View file

@ -1,4 +1,16 @@
import os
from umap.settings.base import * # pylint: disable=W0614,W0401
SECRET_KEY = 'justfortests'
SECRET_KEY = "justfortests"
COMPRESS_ENABLED = False
if "TRAVIS" in os.environ:
DATABASES = {
"default": {
"ENGINE": "django.contrib.gis.db.backends.postgis",
"NAME": "umap",
"PORT": 5433,
"USER": "travis",
}
}

View file

@ -1,5 +1,5 @@
from django.conf import settings
from django.conf.urls import include, url
from django.conf.urls import include, re_path
from django.conf.urls.i18n import i18n_patterns
from django.conf.urls.static import static
from django.contrib import admin
@ -17,74 +17,74 @@ from .utils import decorated_patterns
admin.autodiscover()
urlpatterns = [
url(r'^admin/', admin.site.urls),
url('', include('social_django.urls', namespace='social')),
url(r'^m/(?P<pk>\d+)/$', views.MapShortUrl.as_view(),
re_path(r'^admin/', admin.site.urls),
re_path('', include('social_django.urls', namespace='social')),
re_path(r'^m/(?P<pk>\d+)/$', views.MapShortUrl.as_view(),
name='map_short_url'),
url(r'^ajax-proxy/$', cache_page(180)(views.ajax_proxy),
re_path(r'^ajax-proxy/$', cache_page(180)(views.ajax_proxy),
name='ajax-proxy'),
url(r'^change-password/', auth_views.PasswordChangeView.as_view(),
re_path(r'^change-password/', auth_views.PasswordChangeView.as_view(),
{'template_name': 'umap/password_change.html'},
name='password_change'),
url(r'^change-password-done/', auth_views.PasswordChangeDoneView.as_view(),
re_path(r'^change-password-done/', auth_views.PasswordChangeDoneView.as_view(),
{'template_name': 'umap/password_change_done.html'},
name='password_change_done'),
url(r'^i18n/', include('django.conf.urls.i18n')),
url(r'^agnocomplete/', include('agnocomplete.urls')),
re_path(r'^i18n/', include('django.conf.urls.i18n')),
re_path(r'^agnocomplete/', include('agnocomplete.urls')),
]
i18n_urls = [
url(r'^login/$', jsonize_view(auth_views.LoginView.as_view()), name='login'), # noqa
url(r'^login/popup/end/$', views.LoginPopupEnd.as_view(),
re_path(r'^login/$', jsonize_view(auth_views.LoginView.as_view()), name='login'), # noqa
re_path(r'^login/popup/end/$', views.LoginPopupEnd.as_view(),
name='login_popup_end'),
url(r'^logout/$', views.logout, name='logout'),
url(r'^map/(?P<pk>\d+)/geojson/$', views.MapViewGeoJSON.as_view(),
re_path(r'^logout/$', views.logout, name='logout'),
re_path(r'^map/(?P<pk>\d+)/geojson/$', views.MapViewGeoJSON.as_view(),
name='map_geojson'),
url(r'^map/anonymous-edit/(?P<signature>.+)$',
re_path(r'^map/anonymous-edit/(?P<signature>.+)$',
views.MapAnonymousEditUrl.as_view(), name='map_anonymous_edit_url'),
url(r'^pictogram/json/$', views.PictogramJSONList.as_view(),
re_path(r'^pictogram/json/$', views.PictogramJSONList.as_view(),
name='pictogram_list_json'),
]
i18n_urls += decorated_patterns(cache_control(must_revalidate=True),
url(r'^datalayer/(?P<pk>[\d]+)/$', views.DataLayerView.as_view(), name='datalayer_view'), # noqa
url(r'^datalayer/(?P<pk>[\d]+)/versions/$', views.DataLayerVersions.as_view(), name='datalayer_versions'), # noqa
url(r'^datalayer/(?P<pk>[\d]+)/(?P<name>[_\w]+.geojson)$', views.DataLayerVersion.as_view(), name='datalayer_version'), # noqa
re_path(r'^datalayer/(?P<pk>[\d]+)/$', views.DataLayerView.as_view(), name='datalayer_view'), # noqa
re_path(r'^datalayer/(?P<pk>[\d]+)/versions/$', views.DataLayerVersions.as_view(), name='datalayer_versions'), # noqa
re_path(r'^datalayer/(?P<pk>[\d]+)/(?P<name>[_\w]+.geojson)$', views.DataLayerVersion.as_view(), name='datalayer_version'), # noqa
)
i18n_urls += decorated_patterns([ensure_csrf_cookie],
url(r'^map/(?P<slug>[-_\w]+)_(?P<pk>\d+)$', views.MapView.as_view(), name='map'), # noqa
url(r'^map/new/$', views.MapNew.as_view(), name='map_new'),
re_path(r'^map/(?P<slug>[-_\w]+)_(?P<pk>\d+)$', views.MapView.as_view(), name='map'), # noqa
re_path(r'^map/new/$', views.MapNew.as_view(), name='map_new'),
)
i18n_urls += decorated_patterns(
[login_required_if_not_anonymous_allowed, never_cache],
url(r'^map/create/$', views.MapCreate.as_view(), name='map_create'),
re_path(r'^map/create/$', views.MapCreate.as_view(), name='map_create'),
)
i18n_urls += decorated_patterns(
[map_permissions_check, never_cache],
url(r'^map/(?P<map_id>[\d]+)/update/settings/$', views.MapUpdate.as_view(),
re_path(r'^map/(?P<map_id>[\d]+)/update/settings/$', views.MapUpdate.as_view(),
name='map_update'),
url(r'^map/(?P<map_id>[\d]+)/update/permissions/$',
re_path(r'^map/(?P<map_id>[\d]+)/update/permissions/$',
views.UpdateMapPermissions.as_view(), name='map_update_permissions'),
url(r'^map/(?P<map_id>[\d]+)/update/owner/$',
re_path(r'^map/(?P<map_id>[\d]+)/update/owner/$',
views.AttachAnonymousMap.as_view(), name='map_attach_owner'),
url(r'^map/(?P<map_id>[\d]+)/update/delete/$',
re_path(r'^map/(?P<map_id>[\d]+)/update/delete/$',
views.MapDelete.as_view(), name='map_delete'),
url(r'^map/(?P<map_id>[\d]+)/update/clone/$',
re_path(r'^map/(?P<map_id>[\d]+)/update/clone/$',
views.MapClone.as_view(), name='map_clone'),
url(r'^map/(?P<map_id>[\d]+)/datalayer/create/$',
re_path(r'^map/(?P<map_id>[\d]+)/datalayer/create/$',
views.DataLayerCreate.as_view(), name='datalayer_create'),
url(r'^map/(?P<map_id>[\d]+)/datalayer/update/(?P<pk>\d+)/$',
re_path(r'^map/(?P<map_id>[\d]+)/datalayer/update/(?P<pk>\d+)/$',
views.DataLayerUpdate.as_view(), name='datalayer_update'),
url(r'^map/(?P<map_id>[\d]+)/datalayer/delete/(?P<pk>\d+)/$',
re_path(r'^map/(?P<map_id>[\d]+)/datalayer/delete/(?P<pk>\d+)/$',
views.DataLayerDelete.as_view(), name='datalayer_delete'),
)
urlpatterns += i18n_patterns(
url(r'^$', views.home, name="home"),
url(r'^showcase/$', cache_page(24 * 60 * 60)(views.showcase),
re_path(r'^$', views.home, name="home"),
re_path(r'^showcase/$', cache_page(24 * 60 * 60)(views.showcase),
name='maps_showcase'),
url(r'^search/$', views.search, name="search"),
url(r'^about/$', views.about, name="about"),
url(r'^user/(?P<username>.+)/$', views.user_maps, name='user_maps'),
url(r'', include(i18n_urls)),
re_path(r'^search/$', views.search, name="search"),
re_path(r'^about/$', views.about, name="about"),
re_path(r'^user/(?P<username>.+)/$', views.user_maps, name='user_maps'),
re_path(r'', include(i18n_urls)),
)
if settings.DEBUG and settings.MEDIA_ROOT:

View file

@ -109,3 +109,7 @@ def gzip_file(from_path, to_path):
with open(from_path, 'rb') as f_in:
with gzip.open(to_path, 'wb') as f_out:
f_out.writelines(f_in)
def is_ajax(request):
return request.headers.get('x-requested-with') == 'XMLHttpRequest'

View file

@ -23,7 +23,7 @@ from django.template.loader import render_to_string
from django.urls import reverse, reverse_lazy
from django.utils.encoding import force_bytes, smart_bytes
from django.utils.http import http_date
from django.utils.translation import ugettext as _
from django.utils.translation import gettext as _
from django.utils.translation import to_locale
from django.views.generic import DetailView, TemplateView, View
from django.views.generic.base import RedirectView
@ -35,7 +35,7 @@ from .forms import (DEFAULT_LATITUDE, DEFAULT_LONGITUDE, DEFAULT_CENTER,
AnonymousMapPermissionsForm, DataLayerForm, FlatErrorList,
MapSettingsForm, UpdateMapPermissionsForm)
from .models import DataLayer, Licence, Map, Pictogram, TileLayer
from .utils import get_uri_template, gzip_file
from .utils import get_uri_template, gzip_file, is_ajax
try:
# python3
@ -116,7 +116,7 @@ class Home(TemplateView, PaginatorMixin):
"""
Dispatch template according to the kind of request: ajax or normal.
"""
if self.request.is_ajax():
if is_ajax(self.request):
return [self.list_template_name]
else:
return [self.template_name]
@ -159,7 +159,7 @@ class UserMaps(DetailView, PaginatorMixin):
"""
Dispatch template according to the kind of request: ajax or normal.
"""
if self.request.is_ajax():
if is_ajax(self.request):
return [self.list_template_name]
else:
return super(UserMaps, self).get_template_names()
@ -192,7 +192,7 @@ class Search(TemplateView, PaginatorMixin):
"""
Dispatch template according to the kind of request: ajax or normal.
"""
if self.request.is_ajax():
if is_ajax(self.request):
return [self.list_template_name]
else:
return super(Search, self).get_template_names()
@ -239,7 +239,7 @@ showcase = MapsShowCase.as_view()
def validate_url(request):
assert request.method == "GET"
assert request.is_ajax()
assert is_ajax(request)
url = request.GET.get('url')
assert url
try: