From 03437a3a401ffb383748d1404e19ce6a4273ff74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Sun, 3 Apr 2022 16:33:43 +0200 Subject: [PATCH] update dependencies and upgrade code for django where needed/possible --- src/c3nav/api/__init__.py | 2 - src/c3nav/api/api.py | 2 +- src/c3nav/api/models.py | 2 +- src/c3nav/api/urls.py | 21 +++--- src/c3nav/control/admin.py | 2 +- src/c3nav/control/forms.py | 16 ++-- src/c3nav/control/models.py | 2 +- src/c3nav/control/urls.py | 18 ++--- src/c3nav/control/views.py | 2 +- src/c3nav/editor/__init__.py | 1 - src/c3nav/editor/api.py | 2 +- src/c3nav/editor/converters.py | 8 ++ src/c3nav/editor/forms.py | 2 +- src/c3nav/editor/models/changedobject.py | 2 +- src/c3nav/editor/models/changeset.py | 6 +- src/c3nav/editor/models/changesetupdate.py | 2 +- src/c3nav/editor/urls.py | 50 +++++++------ src/c3nav/editor/views/account.py | 2 +- src/c3nav/editor/views/base.py | 2 +- src/c3nav/editor/views/changes.py | 2 +- src/c3nav/editor/views/edit.py | 2 +- src/c3nav/editor/views/users.py | 2 +- src/c3nav/editor/wrappers.py | 4 +- src/c3nav/mapdata/__init__.py | 1 - src/c3nav/mapdata/api.py | 2 +- src/c3nav/mapdata/converters.py | 48 ++++++++++++ src/c3nav/mapdata/fields.py | 2 +- src/c3nav/mapdata/forms.py | 2 +- .../management/commands/clearmapcache.py | 2 +- .../management/commands/convertstats.py | 2 +- .../mapdata/management/commands/importsvg.py | 2 +- .../management/commands/processupdates.py | 2 +- .../mapdata/management/commands/rendermap.py | 10 +-- .../management/commands/statssnapshot.py | 2 +- src/c3nav/mapdata/models/access.py | 6 +- src/c3nav/mapdata/models/base.py | 2 +- src/c3nav/mapdata/models/geometry/base.py | 2 +- src/c3nav/mapdata/models/geometry/level.py | 2 +- src/c3nav/mapdata/models/geometry/space.py | 2 +- src/c3nav/mapdata/models/graph.py | 2 +- src/c3nav/mapdata/models/level.py | 2 +- src/c3nav/mapdata/models/locations.py | 8 +- src/c3nav/mapdata/models/report.py | 4 +- src/c3nav/mapdata/models/source.py | 2 +- src/c3nav/mapdata/models/update.py | 2 +- src/c3nav/mapdata/tasks.py | 6 +- src/c3nav/mapdata/urls.py | 20 +++-- src/c3nav/mapdata/utils/locations.py | 2 +- src/c3nav/mapdata/utils/user.py | 6 +- src/c3nav/routing/api.py | 2 +- src/c3nav/routing/forms.py | 6 +- src/c3nav/routing/locator.py | 2 +- src/c3nav/routing/models.py | 2 +- src/c3nav/routing/route.py | 2 +- src/c3nav/settings.py | 5 +- src/c3nav/site/converters.py | 53 +++++++++++++ src/c3nav/site/forms.py | 2 +- src/c3nav/site/models.py | 2 +- src/c3nav/site/urls.py | 74 ++++++++++--------- src/c3nav/site/views.py | 29 ++++---- src/c3nav/urls.py | 18 ++--- src/requirements/dev.txt | 4 +- src/requirements/opengl.txt | 2 +- src/requirements/production.txt | 30 ++++---- src/requirements/redis.txt | 4 +- src/requirements/rsvg.txt | 2 +- src/requirements/sentry.txt | 2 +- 67 files changed, 331 insertions(+), 207 deletions(-) create mode 100644 src/c3nav/editor/converters.py create mode 100644 src/c3nav/mapdata/converters.py create mode 100644 src/c3nav/site/converters.py diff --git a/src/c3nav/api/__init__.py b/src/c3nav/api/__init__.py index ed1be8ff..c12a4721 100644 --- a/src/c3nav/api/__init__.py +++ b/src/c3nav/api/__init__.py @@ -5,8 +5,6 @@ from rest_framework.renderers import JSONRenderer from c3nav.mapdata.utils.json import json_encoder_reindent -default_app_config = 'c3nav.api.apps.APIConfig' - orig_render = JSONRenderer.render diff --git a/src/c3nav/api/api.py b/src/c3nav/api/api.py index 8a0a4fb4..1a3cbf10 100644 --- a/src/c3nav/api/api.py +++ b/src/c3nav/api/api.py @@ -1,7 +1,7 @@ from django.contrib.auth import login, logout from django.contrib.auth.forms import AuthenticationForm from django.middleware import csrf -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework.authentication import SessionAuthentication from rest_framework.decorators import action from rest_framework.exceptions import ParseError, PermissionDenied diff --git a/src/c3nav/api/models.py b/src/c3nav/api/models.py index d908a25f..b57aa419 100644 --- a/src/c3nav/api/models.py +++ b/src/c3nav/api/models.py @@ -3,7 +3,7 @@ import string from django.conf import settings from django.db import models from django.utils.crypto import constant_time_compare, get_random_string -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class Token(models.Model): diff --git a/src/c3nav/api/urls.py b/src/c3nav/api/urls.py index 0935808f..ba84b22d 100644 --- a/src/c3nav/api/urls.py +++ b/src/c3nav/api/urls.py @@ -2,7 +2,7 @@ import inspect import re from collections import OrderedDict -from django.conf.urls import include, url +from django.urls import include, path, re_path from django.utils.functional import cached_property from rest_framework.generics import GenericAPIView from rest_framework.response import Response @@ -20,7 +20,7 @@ from c3nav.mapdata.utils.user import can_access_editor from c3nav.routing.api import RoutingViewSet router = SimpleRouter() -router.register(r'map', MapViewSet, base_name='map') +router.register(r'map', MapViewSet, basename='map') router.register(r'levels', LevelViewSet) router.register(r'buildings', BuildingViewSet) router.register(r'spaces', SpaceViewSet) @@ -40,18 +40,18 @@ router.register(r'accessrestrictions', AccessRestrictionViewSet) router.register(r'accessrestrictiongroups', AccessRestrictionGroupViewSet) router.register(r'locations', LocationViewSet) -router.register(r'locations/by_slug', LocationBySlugViewSet, base_name='location-by-slug') -router.register(r'locations/dynamic', DynamicLocationPositionViewSet, base_name='dynamic-location') +router.register(r'locations/by_slug', LocationBySlugViewSet, basename='location-by-slug') +router.register(r'locations/dynamic', DynamicLocationPositionViewSet, basename='dynamic-location') router.register(r'locationgroupcategories', LocationGroupCategoryViewSet) router.register(r'locationgroups', LocationGroupViewSet) -router.register(r'updates', UpdatesViewSet, base_name='updates') +router.register(r'updates', UpdatesViewSet, basename='updates') -router.register(r'routing', RoutingViewSet, base_name='routing') +router.register(r'routing', RoutingViewSet, basename='routing') -router.register(r'editor', EditorViewSet, base_name='editor') +router.register(r'editor', EditorViewSet, basename='editor') router.register(r'changesets', ChangeSetViewSet) -router.register(r'session', SessionViewSet, base_name='session') +router.register(r'session', SessionViewSet, basename='session') class APIRoot(GenericAPIView): @@ -94,6 +94,7 @@ class APIRoot(GenericAPIView): urlpatterns = [ - url(r'^$', APIRoot.as_view()), - url(r'', include(router.urls)), + # todo: does this work? can it be better? + re_path(r'^$', APIRoot.as_view()), + path('', include(router.urls)), ] diff --git a/src/c3nav/control/admin.py b/src/c3nav/control/admin.py index d3471447..59216378 100644 --- a/src/c3nav/control/admin.py +++ b/src/c3nav/control/admin.py @@ -2,7 +2,7 @@ from django.contrib import admin from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.models import User from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.control.models import UserPermissions diff --git a/src/c3nav/control/forms.py b/src/c3nav/control/forms.py index 1a3163a1..c9e73033 100644 --- a/src/c3nav/control/forms.py +++ b/src/c3nav/control/forms.py @@ -11,8 +11,8 @@ from django.contrib.auth.models import User from django.db.models import Prefetch from django.forms import ChoiceField, Form, IntegerField, ModelForm, Select from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ -from django.utils.translation import ungettext_lazy +from django.utils.translation import gettext_lazy as _ +from django.utils.translation import ngettext_lazy from c3nav.control.models import UserPermissions, UserSpaceAccess from c3nav.mapdata.forms import I18nModelFormMixin @@ -81,9 +81,9 @@ class AccessPermissionForm(Form): # construct choice field for access permissions choices = [('', _('choose permissions…')), - ('all', ungettext_lazy('everything possible (%d permission)', - 'everything possible (%d permissions)', - len(access_restrictions)) % len(access_restrictions))] + ('all', ngettext_lazy('everything possible (%d permission)', + 'everything possible (%d permissions)', + len(access_restrictions)) % len(access_restrictions))] choices.append((_('Access Permission Groups'), tuple( ('g%d' % group.pk, group.title) @@ -102,18 +102,18 @@ class AccessPermissionForm(Form): ] for minutes in range(15, 60, 15): expire_choices.append( - (str(minutes), ungettext_lazy('in %d minute', 'in %d minutes', minutes) % minutes)) + (str(minutes), ngettext_lazy('in %d minute', 'in %d minutes', minutes) % minutes)) for hours in chain(range(1, 6), range(6, 24, 6)): expire_choices.append( - (str(hours*60), ungettext_lazy('in %d hour', 'in %d hours', hours) % hours) + (str(hours*60), ngettext_lazy('in %d hour', 'in %d hours', hours) % hours) ) expire_choices.insert( 5, (str(90), _('in 1½ hour')) ) for days in range(1, 14): expire_choices.append( - (str(days*24*60), ungettext_lazy('in %d day', 'in %d days', days) % days) + (str(days*24*60), ngettext_lazy('in %d day', 'in %d days', days) % days) ) self.fields['expires'] = ChoiceField(required=False, initial='60', choices=expire_choices) diff --git a/src/c3nav/control/models.py b/src/c3nav/control/models.py index ee89555f..808b08ab 100644 --- a/src/c3nav/control/models.py +++ b/src/c3nav/control/models.py @@ -6,7 +6,7 @@ from django.contrib.auth.models import User from django.core.cache import cache from django.db import models, transaction from django.utils.functional import cached_property, lazy -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.mapdata.models import Space diff --git a/src/c3nav/control/urls.py b/src/c3nav/control/urls.py index 8ec281f9..28ae4a1f 100644 --- a/src/c3nav/control/urls.py +++ b/src/c3nav/control/urls.py @@ -1,15 +1,15 @@ -from django.conf.urls import url +from django.urls import path from c3nav.control.views import (announcement_detail, announcement_list, grant_access, grant_access_qr, main_index, map_updates, user_detail, user_list) urlpatterns = [ - url(r'^users/$', user_list, name='control.users'), - url(r'^users/(?P\d+)/$', user_detail, name='control.users.detail'), - url(r'^access/$', grant_access, name='control.access'), - url(r'^access/(?P[^/]+)$', grant_access_qr, name='control.access.qr'), - url(r'^announcements/$', announcement_list, name='control.announcements'), - url(r'^announcements/(?P\d+)/$', announcement_detail, name='control.announcements.detail'), - url(r'^mapupdates/$', map_updates, name='control.map_updates'), - url(r'^$', main_index, name='control.index'), + path('users/', user_list, name='control.users'), + path('users//', user_detail, name='control.users.detail'), + path('access/', grant_access, name='control.access'), + path('access/', grant_access_qr, name='control.access.qr'), + path('announcements/', announcement_list, name='control.announcements'), + path('announcements//', announcement_detail, name='control.announcements.detail'), + path('mapupdates/', map_updates, name='control.map_updates'), + path('', main_index, name='control.index'), ] diff --git a/src/c3nav/control/views.py b/src/c3nav/control/views.py index e3968273..1c939f0d 100644 --- a/src/c3nav/control/views.py +++ b/src/c3nav/control/views.py @@ -17,7 +17,7 @@ from django.urls import reverse from django.utils import timezone from django.utils.crypto import get_random_string from django.utils.timezone import make_aware -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.control.forms import (AccessPermissionForm, AnnouncementForm, MapUpdateFilterForm, MapUpdateForm, UserPermissionsForm, UserSpaceAccessForm) diff --git a/src/c3nav/editor/__init__.py b/src/c3nav/editor/__init__.py index 01e2b19a..e69de29b 100644 --- a/src/c3nav/editor/__init__.py +++ b/src/c3nav/editor/__init__.py @@ -1 +0,0 @@ -default_app_config = 'c3nav.editor.apps.EditorConfig' diff --git a/src/c3nav/editor/api.py b/src/c3nav/editor/api.py index 08ab98bd..7cd2b8ef 100644 --- a/src/c3nav/editor/api.py +++ b/src/c3nav/editor/api.py @@ -4,7 +4,7 @@ from itertools import chain from django.db.models import Prefetch, Q from django.urls import Resolver404, resolve from django.utils.functional import cached_property -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework.authentication import SessionAuthentication from rest_framework.decorators import action from rest_framework.exceptions import NotFound, ParseError, PermissionDenied, ValidationError diff --git a/src/c3nav/editor/converters.py b/src/c3nav/editor/converters.py new file mode 100644 index 00000000..53afc062 --- /dev/null +++ b/src/c3nav/editor/converters.py @@ -0,0 +1,8 @@ +class EditPkConverter: + regex = r'c?\d+' + + def to_python(self, value): + return value + + def to_url(self, value): + return value diff --git a/src/c3nav/editor/forms.py b/src/c3nav/editor/forms.py index 85d0a336..239e7a7c 100644 --- a/src/c3nav/editor/forms.py +++ b/src/c3nav/editor/forms.py @@ -13,7 +13,7 @@ from django.db.models import Q from django.forms import (BooleanField, CharField, ChoiceField, DecimalField, Form, ModelChoiceField, ModelForm, MultipleChoiceField, Select, ValidationError) from django.forms.widgets import HiddenInput -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from shapely.geometry.geo import mapping from c3nav.editor.models import ChangeSet, ChangeSetUpdate diff --git a/src/c3nav/editor/models/changedobject.py b/src/c3nav/editor/models/changedobject.py index eb531922..bb6e6974 100644 --- a/src/c3nav/editor/models/changedobject.py +++ b/src/c3nav/editor/models/changedobject.py @@ -6,7 +6,7 @@ from itertools import chain from django.contrib.contenttypes.models import ContentType from django.db import models from django.db.models import CharField, DecimalField, Field, TextField -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.editor.wrappers import ModelInstanceWrapper, is_created_pk from c3nav.mapdata.fields import I18nField, JSONField diff --git a/src/c3nav/editor/models/changeset.py b/src/c3nav/editor/models/changeset.py index 110c76b9..0857ca43 100644 --- a/src/c3nav/editor/models/changeset.py +++ b/src/c3nav/editor/models/changeset.py @@ -14,8 +14,8 @@ from django.db.models import Q from django.urls import reverse from django.utils.http import int_to_base36 from django.utils.timezone import make_naive -from django.utils.translation import ugettext_lazy as _ -from django.utils.translation import ungettext_lazy +from django.utils.translation import gettext_lazy as _ +from django.utils.translation import ngettext_lazy from c3nav.editor.models.changedobject import ApplyToInstanceError, ChangedObject, NoopChangedObject from c3nav.editor.tasks import send_changeset_proposed_notification @@ -804,7 +804,7 @@ class ChangeSet(models.Model): if self.direct_editing: return _('Direct editing active') return _('No objects changed') - return (ungettext_lazy('%(num)d object changed', '%(num)d objects changed', 'num') % + return (ngettext_lazy('%(num)d object changed', '%(num)d objects changed', 'num') % {'num': self.changed_objects_count}) @property diff --git a/src/c3nav/editor/models/changesetupdate.py b/src/c3nav/editor/models/changesetupdate.py index 0201a875..2dd90f3c 100644 --- a/src/c3nav/editor/models/changesetupdate.py +++ b/src/c3nav/editor/models/changesetupdate.py @@ -2,7 +2,7 @@ from collections import OrderedDict from django.conf import settings from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.editor.models import ChangeSet diff --git a/src/c3nav/editor/urls.py b/src/c3nav/editor/urls.py index 79d28335..276880d2 100644 --- a/src/c3nav/editor/urls.py +++ b/src/c3nav/editor/urls.py @@ -1,11 +1,14 @@ from django.apps import apps -from django.conf.urls import url +from django.urls import path, register_converter +from c3nav.editor.converters import EditPkConverter from c3nav.editor.views.account import change_password_view, login_view, logout_view, register_view from c3nav.editor.views.changes import changeset_detail, changeset_edit, changeset_redirect from c3nav.editor.views.edit import edit, graph_edit, level_detail, list_objects, main_index, sourceimage, space_detail from c3nav.editor.views.users import user_detail, user_redirect +register_converter(EditPkConverter, 'editpk') + def add_editor_urls(model_name, parent_model_name=None, with_list=True, explicit_edit=False): model = apps.get_model('mapdata', model_name) @@ -13,42 +16,43 @@ def add_editor_urls(model_name, parent_model_name=None, with_list=True, explicit if parent_model_name: parent_model = apps.get_model('mapdata', parent_model_name) parent_model_name_plural = parent_model._meta.default_related_name - prefix = (parent_model_name_plural+r'/(?P<'+parent_model_name.lower()+'>c?[0-9]+)/')+model_name_plural + prefix = (parent_model_name_plural+r'//')+model_name_plural else: prefix = model_name_plural name_prefix = 'editor.'+model_name_plural+'.' kwargs = {'model': model_name, 'explicit_edit': explicit_edit} - explicit_edit = r'edit' if explicit_edit else '' + explicit_edit = 'edit' if explicit_edit else '' result = [] if with_list: - result.append(url(r'^'+prefix+r'/$', list_objects, name=name_prefix+'list', kwargs=kwargs)) + result.append(path(prefix+'/', list_objects, name=name_prefix+'list', kwargs=kwargs)) result.extend([ - url(r'^'+prefix+r'/(?Pc?\d+)/'+explicit_edit+'$', edit, name=name_prefix+'edit', kwargs=kwargs), - url(r'^'+prefix+r'/create$', edit, name=name_prefix+'create', kwargs=kwargs), + path(prefix+'//'+explicit_edit, edit, name=name_prefix+'edit', kwargs=kwargs), + path(prefix+'/create', edit, name=name_prefix+'create', kwargs=kwargs), ]) return result +# todo: custom path converters urlpatterns = [ - url(r'^$', main_index, name='editor.index'), - url(r'^levels/(?Pc?[0-9]+)/$', level_detail, name='editor.levels.detail'), - url(r'^levels/(?Pc?[0-9]+)/spaces/(?Pc?[0-9]+)/$', space_detail, name='editor.spaces.detail'), - url(r'^levels/(?Pc?[0-9]+)/levels_on_top/create$', edit, name='editor.levels_on_top.create', - kwargs={'model': 'Level'}), - url(r'^levels/(?Pc?[0-9]+)/graph/$', graph_edit, name='editor.levels.graph'), - url(r'^spaces/(?Pc?[0-9]+)/graph/$', graph_edit, name='editor.spaces.graph'), - url(r'^changeset/$', changeset_redirect, name='editor.changesets.current'), - url(r'^changesets/(?P[0-9]+)/$', changeset_detail, name='editor.changesets.detail'), - url(r'^changesets/(?P[0-9]+)/edit$', changeset_edit, name='editor.changesets.edit'), - url(r'^sourceimage/(?P[^/]+)$', sourceimage, name='editor.sourceimage'), - url(r'^user/$', user_redirect, name='editor.users.redirect'), - url(r'^users/(?P[0-9]+)/$', user_detail, name='editor.users.detail'), - url(r'^login$', login_view, name='editor.login'), - url(r'^logout$', logout_view, name='editor.logout'), - url(r'^register$', register_view, name='editor.register'), - url(r'^change_password$', change_password_view, name='editor.change_password'), + path('levels//', level_detail, name='editor.levels.detail'), + path('levels//spaces//', space_detail, name='editor.spaces.detail'), + path('levels//levels_on_top/create', edit, {'model': 'Level'}, + name='editor.levels_on_top.create'), + path('levels//graph/', graph_edit, name='editor.levels.graph'), + path('spaces//graph/', graph_edit, name='editor.spaces.graph'), + path('changeset/', changeset_redirect, name='editor.changesets.current'), + path('changesets//', changeset_detail, name='editor.changesets.detail'), + path('changesets//edit', changeset_edit, name='editor.changesets.edit'), + path('sourceimage/', sourceimage, name='editor.sourceimage'), + path('user/', user_redirect, name='editor.users.redirect'), + path('users//', user_detail, name='editor.users.detail'), + path('login', login_view, name='editor.login'), + path('logout', logout_view, name='editor.logout'), + path('register', register_view, name='editor.register'), + path('change_password', change_password_view, name='editor.change_password'), + path('', main_index, name='editor.index'), ] urlpatterns.extend(add_editor_urls('Level', with_list=False, explicit_edit=True)) urlpatterns.extend(add_editor_urls('LocationGroupCategory')) diff --git a/src/c3nav/editor/views/account.py b/src/c3nav/editor/views/account.py index 6842c054..b4b1c5c2 100644 --- a/src/c3nav/editor/views/account.py +++ b/src/c3nav/editor/views/account.py @@ -4,7 +4,7 @@ from django.contrib.auth.decorators import login_required from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm, UserCreationForm from django.shortcuts import redirect, render from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.editor.views.base import sidebar_view diff --git a/src/c3nav/editor/views/base.py b/src/c3nav/editor/views/base.py index b216fb69..fd0c6124 100644 --- a/src/c3nav/editor/views/base.py +++ b/src/c3nav/editor/views/base.py @@ -13,7 +13,7 @@ from django.http import HttpResponse, HttpResponseNotModified, HttpResponseRedir from django.shortcuts import redirect, render from django.utils.cache import patch_vary_headers from django.utils.translation import get_language -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework.response import Response as APIResponse from c3nav.editor.models import ChangeSet diff --git a/src/c3nav/editor/views/changes.py b/src/c3nav/editor/views/changes.py index ef457d77..579b6c99 100644 --- a/src/c3nav/editor/views/changes.py +++ b/src/c3nav/editor/views/changes.py @@ -10,7 +10,7 @@ from django.shortcuts import get_object_or_404, redirect, render from django.urls import NoReverseMatch, reverse from django.utils.text import format_lazy from django.utils.translation import get_language_info -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.editor.forms import ChangeSetForm, RejectForm from c3nav.editor.models import ChangeSet diff --git a/src/c3nav/editor/views/edit.py b/src/c3nav/editor/views/edit.py index 402c2f1e..7bb94c3e 100644 --- a/src/c3nav/editor/views/edit.py +++ b/src/c3nav/editor/views/edit.py @@ -12,7 +12,7 @@ from django.db.models import Q from django.http import Http404, HttpResponse from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.views.decorators.http import etag from c3nav.editor.forms import GraphEdgeSettingsForm, GraphEditorActionForm diff --git a/src/c3nav/editor/views/users.py b/src/c3nav/editor/views/users.py index 10ed928d..975305e4 100644 --- a/src/c3nav/editor/views/users.py +++ b/src/c3nav/editor/views/users.py @@ -2,7 +2,7 @@ from django.contrib import messages from django.contrib.auth.models import User from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.editor.models import ChangeSet from c3nav.editor.views.base import sidebar_view diff --git a/src/c3nav/editor/wrappers.py b/src/c3nav/editor/wrappers.py index 0eafe1cf..adb03758 100644 --- a/src/c3nav/editor/wrappers.py +++ b/src/c3nav/editor/wrappers.py @@ -5,9 +5,9 @@ from functools import reduce, wraps from itertools import chain from django.core.cache import cache -from django.core.exceptions import ObjectDoesNotExist +from django.core.exceptions import ObjectDoesNotExist, FieldDoesNotExist from django.db import models -from django.db.models import FieldDoesNotExist, Manager, ManyToManyRel, Prefetch, Q +from django.db.models import Manager, ManyToManyRel, Prefetch, Q from django.db.models.fields.related_descriptors import ReverseOneToOneDescriptor from django.utils.functional import cached_property diff --git a/src/c3nav/mapdata/__init__.py b/src/c3nav/mapdata/__init__.py index d441434e..e69de29b 100644 --- a/src/c3nav/mapdata/__init__.py +++ b/src/c3nav/mapdata/__init__.py @@ -1 +0,0 @@ -default_app_config = 'c3nav.mapdata.apps.MapdataConfig' diff --git a/src/c3nav/mapdata/api.py b/src/c3nav/mapdata/api.py index a97dce3e..603dc4c4 100644 --- a/src/c3nav/mapdata/api.py +++ b/src/c3nav/mapdata/api.py @@ -11,7 +11,7 @@ from django.shortcuts import redirect from django.utils.cache import get_conditional_response from django.utils.http import http_date, quote_etag, urlsafe_base64_encode from django.utils.translation import get_language -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework.decorators import action from rest_framework.exceptions import NotFound, ValidationError from rest_framework.generics import get_object_or_404 diff --git a/src/c3nav/mapdata/converters.py b/src/c3nav/mapdata/converters.py new file mode 100644 index 00000000..bba88976 --- /dev/null +++ b/src/c3nav/mapdata/converters.py @@ -0,0 +1,48 @@ +class SignedIntConverter: + regex = r'-?\d+' + + def to_python(self, value): + return int(value) + + def to_url(self, value): + return str(value) + + +class AccessPermissionsConverter: + regex = r'\d+(-\d+)*' + + def to_python(self, value): + return set(int(i) for i in value.split('-')) + + def to_url(self, value): + return '-'.join(str(i) for i in value) + + +class HistoryModeConverter: + regex = '(base|composite)' + + def to_python(self, value): + return value + + def to_url(self, value): + return value + + +class HistoryFileExtConverter: + regex = '(png|data)' + + def to_python(self, value): + return value + + def to_url(self, value): + return value + + +class ArchiveFileExtConverter: + regex = r'(tar|tar\.gz|tar\.xz)' + + def to_python(self, value): + return value + + def to_url(self, value): + return value diff --git a/src/c3nav/mapdata/fields.py b/src/c3nav/mapdata/fields.py index e3d14af3..59cd7590 100644 --- a/src/c3nav/mapdata/fields.py +++ b/src/c3nav/mapdata/fields.py @@ -9,7 +9,7 @@ from django.db import models from django.utils.functional import cached_property, lazy from django.utils.text import format_lazy from django.utils.translation import get_language -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from shapely import validation from shapely.geometry import LineString, MultiPolygon, Point, Polygon, mapping, shape from shapely.geometry.base import BaseGeometry diff --git a/src/c3nav/mapdata/forms.py b/src/c3nav/mapdata/forms.py index 157441c4..00116cad 100644 --- a/src/c3nav/mapdata/forms.py +++ b/src/c3nav/mapdata/forms.py @@ -6,7 +6,7 @@ from django.forms import CharField, ModelForm from django.utils import timezone from django.utils.text import capfirst, format_lazy from django.utils.translation import get_language_info -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.mapdata.fields import I18nField from c3nav.mapdata.models.locations import Position diff --git a/src/c3nav/mapdata/management/commands/clearmapcache.py b/src/c3nav/mapdata/management/commands/clearmapcache.py index d9d12e25..967efc4b 100644 --- a/src/c3nav/mapdata/management/commands/clearmapcache.py +++ b/src/c3nav/mapdata/management/commands/clearmapcache.py @@ -4,7 +4,7 @@ import os from django.conf import settings from django.core.management.base import BaseCommand from django.db import DatabaseError -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.mapdata.tasks import process_map_updates diff --git a/src/c3nav/mapdata/management/commands/convertstats.py b/src/c3nav/mapdata/management/commands/convertstats.py index bc457597..fef1bdba 100644 --- a/src/c3nav/mapdata/management/commands/convertstats.py +++ b/src/c3nav/mapdata/management/commands/convertstats.py @@ -5,7 +5,7 @@ import socket import dateutil from django.conf import settings from django.core.management.base import BaseCommand -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.mapdata.utils.cache.stats import convert_stats diff --git a/src/c3nav/mapdata/management/commands/importsvg.py b/src/c3nav/mapdata/management/commands/importsvg.py index 35fad013..5ec55727 100644 --- a/src/c3nav/mapdata/management/commands/importsvg.py +++ b/src/c3nav/mapdata/management/commands/importsvg.py @@ -4,7 +4,7 @@ import re from xml.etree import ElementTree from django.core.management.base import BaseCommand, CommandError -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from shapely.affinity import scale, translate from shapely.geometry import Polygon diff --git a/src/c3nav/mapdata/management/commands/processupdates.py b/src/c3nav/mapdata/management/commands/processupdates.py index b2cc9423..c2273b4a 100644 --- a/src/c3nav/mapdata/management/commands/processupdates.py +++ b/src/c3nav/mapdata/management/commands/processupdates.py @@ -3,7 +3,7 @@ import logging from django.conf import settings from django.core.management.base import BaseCommand from django.db import DatabaseError -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.mapdata.tasks import process_map_updates diff --git a/src/c3nav/mapdata/management/commands/rendermap.py b/src/c3nav/mapdata/management/commands/rendermap.py index a6f54f2b..4c7fa226 100644 --- a/src/c3nav/mapdata/management/commands/rendermap.py +++ b/src/c3nav/mapdata/management/commands/rendermap.py @@ -3,8 +3,8 @@ import os from django.conf import settings from django.core.management.base import BaseCommand, CommandError -from django.utils.translation import ugettext_lazy as _ -from django.utils.translation import ungettext_lazy +from django.utils.translation import gettext_lazy as _ +from django.utils.translation import ngettext_lazy from c3nav.mapdata.models import AccessRestriction, Level, Source from c3nav.mapdata.render.engines import get_engine, get_engine_filetypes @@ -25,7 +25,7 @@ class Command(BaseCommand): not_found = values - set(level.short_label for level in levels) if not_found: raise argparse.ArgumentTypeError( - ungettext_lazy('Unknown level: %s', 'Unknown levels: %s', len(not_found)) % ', '.join(not_found) + ngettext_lazy('Unknown level: %s', 'Unknown levels: %s', len(not_found)) % ', '.join(not_found) ) return levels @@ -43,8 +43,8 @@ class Command(BaseCommand): not_found = values - set(str(permission.pk) for permission in permissions) if not_found: raise argparse.ArgumentTypeError( - ungettext_lazy('Unknown access restriction: %s', - 'Unknown access restrictions: %s', len(not_found)) % ', '.join(not_found) + ngettext_lazy('Unknown access restriction: %s', + 'Unknown access restrictions: %s', len(not_found)) % ', '.join(not_found) ) return permissions diff --git a/src/c3nav/mapdata/management/commands/statssnapshot.py b/src/c3nav/mapdata/management/commands/statssnapshot.py index a8b10b7d..b189b37d 100644 --- a/src/c3nav/mapdata/management/commands/statssnapshot.py +++ b/src/c3nav/mapdata/management/commands/statssnapshot.py @@ -3,7 +3,7 @@ import os from django.conf import settings from django.core.management.base import BaseCommand -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.mapdata.utils.cache.stats import stats_snapshot diff --git a/src/c3nav/mapdata/models/access.py b/src/c3nav/mapdata/models/access.py index 3e128f7c..431bd346 100644 --- a/src/c3nav/mapdata/models/access.py +++ b/src/c3nav/mapdata/models/access.py @@ -9,8 +9,8 @@ from django.core.cache import cache from django.db import models, transaction from django.db.models import Q from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ -from django.utils.translation import ungettext_lazy +from django.utils.translation import gettext_lazy as _ +from django.utils.translation import ngettext_lazy from c3nav.mapdata.models import MapUpdate from c3nav.mapdata.models.base import SerializableMixin, TitledMixin @@ -130,7 +130,7 @@ class AccessPermissionToken(models.Model): @property def redeem_success_message(self): - return ungettext_lazy('Area successfully unlocked.', 'Areas successfully unlocked.', len(self.restrictions)) + return ngettext_lazy('Area successfully unlocked.', 'Areas successfully unlocked.', len(self.restrictions)) class AccessPermission(models.Model): diff --git a/src/c3nav/mapdata/models/base.py b/src/c3nav/mapdata/models/base.py index f6b4e4c9..66b5ecac 100644 --- a/src/c3nav/mapdata/models/base.py +++ b/src/c3nav/mapdata/models/base.py @@ -4,7 +4,7 @@ from django.core.cache import cache from django.db import models from django.db.models import Q from django.utils.translation import get_language, get_language_info -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.mapdata.fields import I18nField from c3nav.mapdata.models import MapUpdate diff --git a/src/c3nav/mapdata/models/geometry/base.py b/src/c3nav/mapdata/models/geometry/base.py index 55fd7d0e..9de07b14 100644 --- a/src/c3nav/mapdata/models/geometry/base.py +++ b/src/c3nav/mapdata/models/geometry/base.py @@ -3,7 +3,7 @@ from contextlib import contextmanager from django.db import models from django.utils.functional import cached_property -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from shapely.geometry import Point, box from shapely.ops import unary_union diff --git a/src/c3nav/mapdata/models/geometry/level.py b/src/c3nav/mapdata/models/geometry/level.py index 218401aa..2b69fd90 100644 --- a/src/c3nav/mapdata/models/geometry/level.py +++ b/src/c3nav/mapdata/models/geometry/level.py @@ -10,7 +10,7 @@ from django.db import models from django.urls import reverse from django.utils.functional import cached_property from django.utils.text import format_lazy -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from scipy.sparse.csgraph._shortest_path import dijkstra from shapely import prepared from shapely.affinity import scale diff --git a/src/c3nav/mapdata/models/geometry/space.py b/src/c3nav/mapdata/models/geometry/space.py index 8eb5cd0b..29263e93 100644 --- a/src/c3nav/mapdata/models/geometry/space.py +++ b/src/c3nav/mapdata/models/geometry/space.py @@ -7,7 +7,7 @@ from django.db import models from django.urls import reverse from django.utils.functional import cached_property from django.utils.text import format_lazy -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from shapely.geometry import CAP_STYLE, JOIN_STYLE, mapping from c3nav.mapdata.fields import GeometryField, I18nField, JSONField diff --git a/src/c3nav/mapdata/models/graph.py b/src/c3nav/mapdata/models/graph.py index 5fdbd674..834fd991 100644 --- a/src/c3nav/mapdata/models/graph.py +++ b/src/c3nav/mapdata/models/graph.py @@ -2,7 +2,7 @@ from decimal import Decimal from django.core.validators import MinValueValidator from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.mapdata.fields import GeometryField, I18nField from c3nav.mapdata.models.access import AccessRestrictionMixin diff --git a/src/c3nav/mapdata/models/level.py b/src/c3nav/mapdata/models/level.py index 2c691923..a9e381e3 100644 --- a/src/c3nav/mapdata/models/level.py +++ b/src/c3nav/mapdata/models/level.py @@ -6,7 +6,7 @@ from django.core.validators import MinValueValidator from django.db import models from django.urls import reverse from django.utils.functional import cached_property -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from shapely.ops import cascaded_union from c3nav.mapdata.models.locations import SpecificLocation diff --git a/src/c3nav/mapdata/models/locations.py b/src/c3nav/mapdata/models/locations.py index 11219429..31188b7f 100644 --- a/src/c3nav/mapdata/models/locations.py +++ b/src/c3nav/mapdata/models/locations.py @@ -6,16 +6,16 @@ from operator import attrgetter from django.conf import settings from django.core.cache import cache +from django.core.exceptions import FieldDoesNotExist from django.core.validators import MaxValueValidator, MinValueValidator, RegexValidator from django.db import models, transaction -from django.db.models import FieldDoesNotExist, Prefetch +from django.db.models import Prefetch from django.urls import reverse from django.utils import timezone from django.utils.crypto import get_random_string from django.utils.functional import cached_property from django.utils.text import format_lazy -from django.utils.translation import ugettext_lazy as _ -from django.utils.translation import ungettext_lazy +from django.utils.translation import gettext_lazy as _, ngettext_lazy from c3nav.mapdata.fields import I18nField from c3nav.mapdata.grid import grid @@ -396,7 +396,7 @@ class LocationGroup(Location, models.Model): if hasattr(self, 'locations'): return format_lazy(_('{category_title}, {num_locations}'), category_title=result, - num_locations=(ungettext_lazy('%(num)d location', '%(num)d locations', 'num') % + num_locations=(ngettext_lazy('%(num)d location', '%(num)d locations', 'num') % {'num': len(self.locations)})) return result diff --git a/src/c3nav/mapdata/models/report.py b/src/c3nav/mapdata/models/report.py index 661001a8..c7ac8d77 100644 --- a/src/c3nav/mapdata/models/report.py +++ b/src/c3nav/mapdata/models/report.py @@ -8,7 +8,7 @@ from django.db.models import Q from django.urls import reverse from django.utils.crypto import get_random_string from django.utils.functional import cached_property -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.mapdata.fields import I18nField from c3nav.mapdata.models.geometry.level import LevelGeometryMixin @@ -172,7 +172,7 @@ class ReportUpdate(models.Model): report = models.ForeignKey(Report, on_delete=models.CASCADE, related_name='updates') datetime = models.DateTimeField(auto_now_add=True, verbose_name=_('datetime')) author = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.PROTECT, verbose_name=_('author')) - open = models.NullBooleanField(verbose_name=_('open')) + open = models.BooleanField(null=True, verbose_name=_('open')) comment = models.TextField(verbose_name=_('comment'), blank=True) assigned_to = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.PROTECT, related_name='report_update_assigns', verbose_name=_('assigned to')) diff --git a/src/c3nav/mapdata/models/source.py b/src/c3nav/mapdata/models/source.py index d39c3035..6a20a7f0 100644 --- a/src/c3nav/mapdata/models/source.py +++ b/src/c3nav/mapdata/models/source.py @@ -2,7 +2,7 @@ import os from django.conf import settings from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.mapdata.models.access import AccessRestrictionMixin from c3nav.mapdata.models.base import BoundsMixin diff --git a/src/c3nav/mapdata/models/update.py b/src/c3nav/mapdata/models/update.py index 2aa1e945..a51e9e47 100644 --- a/src/c3nav/mapdata/models/update.py +++ b/src/c3nav/mapdata/models/update.py @@ -10,7 +10,7 @@ from django.core.cache import cache from django.db import models, transaction from django.utils.http import int_to_base36 from django.utils.timezone import make_naive -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.mapdata.tasks import process_map_updates diff --git a/src/c3nav/mapdata/tasks.py b/src/c3nav/mapdata/tasks.py index 3a0f806f..4d9c9e6c 100644 --- a/src/c3nav/mapdata/tasks.py +++ b/src/c3nav/mapdata/tasks.py @@ -4,8 +4,8 @@ import time from celery.exceptions import MaxRetriesExceededError from django.core.cache import cache from django.utils.formats import date_format -from django.utils.translation import ugettext_lazy as _ -from django.utils.translation import ungettext_lazy +from django.utils.translation import gettext_lazy as _ +from django.utils.translation import ngettext_lazy from c3nav.celery import app @@ -40,7 +40,7 @@ def process_map_updates(self): if updates: print() - logger.info(ungettext_lazy('%d map update processed.', '%d map updates processed.', len(updates)) % len(updates)) + logger.info(ngettext_lazy('%d map update processed.', '%d map updates processed.', len(updates)) % len(updates)) if updates: logger.info(_('Last processed update: %(date)s (#%(id)d)') % { diff --git a/src/c3nav/mapdata/urls.py b/src/c3nav/mapdata/urls.py index 2fed57c3..3fed7325 100644 --- a/src/c3nav/mapdata/urls.py +++ b/src/c3nav/mapdata/urls.py @@ -1,12 +1,18 @@ -from django.conf.urls import url +from django.urls import path, register_converter +from c3nav.mapdata.converters import SignedIntConverter, AccessPermissionsConverter, HistoryModeConverter, \ + HistoryFileExtConverter, ArchiveFileExtConverter from c3nav.mapdata.views import get_cache_package, map_history, tile +register_converter(SignedIntConverter, 'sint') +register_converter(AccessPermissionsConverter, 'a_perms') +register_converter(HistoryModeConverter, 'h_mode') +register_converter(HistoryFileExtConverter, 'h_fileext') +register_converter(ArchiveFileExtConverter, 'archive_fileext') + urlpatterns = [ - url(r'^(?P\d+)/(?P-?\d+)/(?P-?\d+)/(?P-?\d+).png$', tile, name='mapdata.tile'), - url(r'^(?P\d+)/(?P-?\d+)/(?P-?\d+)/(?P-?\d+)/(?P\d+(-\d+)*).png$', tile, - name='mapdata.tile'), - url(r'^history/(?P\d+)/(?Pbase|composite)\.(?Ppng|data)$', map_history, - name='mapdata.map_history'), - url(r'^cache/package\.(?Ptar|tar\.gz|tar\.xz)$', get_cache_package, name='mapdata.cache_package'), + path('///.png', tile, name='mapdata.tile'), + path('////.png', tile, name='mapdata.tile'), + path('history//.', map_history, name='mapdata.map_history'), + path('cache/package.', get_cache_package, name='mapdata.cache_package'), ] diff --git a/src/c3nav/mapdata/utils/locations.py b/src/c3nav/mapdata/utils/locations.py index 55b9f9ab..76b87a0b 100644 --- a/src/c3nav/mapdata/utils/locations.py +++ b/src/c3nav/mapdata/utils/locations.py @@ -9,7 +9,7 @@ from typing import List, Mapping, Optional, Union from django.apps import apps from django.db.models import Prefetch, Q from django.utils.functional import cached_property -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from shapely.ops import cascaded_union from c3nav.mapdata.grid import grid diff --git a/src/c3nav/mapdata/utils/user.py b/src/c3nav/mapdata/utils/user.py index fd5abdc6..2e5d402d 100644 --- a/src/c3nav/mapdata/utils/user.py +++ b/src/c3nav/mapdata/utils/user.py @@ -1,7 +1,7 @@ from django.conf import settings from django.utils.functional import lazy -from django.utils.translation import ugettext_lazy as _ -from django.utils.translation import ungettext_lazy +from django.utils.translation import gettext_lazy as _ +from django.utils.translation import ngettext_lazy from c3nav.mapdata.models.access import AccessPermission from c3nav.mapdata.models.locations import Position @@ -18,7 +18,7 @@ def get_user_data(request): if permissions: result.update({ 'title': _('not logged in'), - 'subtitle': ungettext_lazy('%d area unlocked', '%d areas unlocked', len(permissions)) % len(permissions), + 'subtitle': ngettext_lazy('%d area unlocked', '%d areas unlocked', len(permissions)) % len(permissions), 'permissions': tuple(permissions), }) else: diff --git a/src/c3nav/routing/api.py b/src/c3nav/routing/api.py index 7d791b1c..59e04c4b 100644 --- a/src/c3nav/routing/api.py +++ b/src/c3nav/routing/api.py @@ -1,6 +1,6 @@ from django.core.exceptions import ValidationError from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.viewsets import ViewSet diff --git a/src/c3nav/routing/forms.py b/src/c3nav/routing/forms.py index 7d53ec48..1c8b8279 100644 --- a/src/c3nav/routing/forms.py +++ b/src/c3nav/routing/forms.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import ugettext_lazy +from django.utils.translation import gettext_lazy from c3nav.mapdata.utils.locations import get_location_by_id_for_request @@ -15,11 +15,11 @@ class RouteForm(forms.Form): def clean_origin(self): location = get_location_by_id_for_request(self.cleaned_data['origin'], self.request) if location is None: - raise forms.ValidationError(ugettext_lazy('Unknown origin.')) + raise forms.ValidationError(gettext_lazy('Unknown origin.')) return location def clean_destination(self): location = get_location_by_id_for_request(self.cleaned_data['destination'], self.request) if location is None: - raise forms.ValidationError(ugettext_lazy('Unknown destination.')) + raise forms.ValidationError(gettext_lazy('Unknown destination.')) return location diff --git a/src/c3nav/routing/locator.py b/src/c3nav/routing/locator.py index b6d49271..4f92c1bd 100644 --- a/src/c3nav/routing/locator.py +++ b/src/c3nav/routing/locator.py @@ -9,7 +9,7 @@ from functools import reduce import numpy as np from django.conf import settings from django.core.exceptions import ValidationError -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.mapdata.models import MapUpdate, Space from c3nav.mapdata.utils.locations import CustomLocation diff --git a/src/c3nav/routing/models.py b/src/c3nav/routing/models.py index 652a4f4f..f66cf910 100644 --- a/src/c3nav/routing/models.py +++ b/src/c3nav/routing/models.py @@ -6,7 +6,7 @@ from django.conf import settings from django.core.cache import cache from django.core.exceptions import ValidationError from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.mapdata.fields import JSONField from c3nav.mapdata.models import MapUpdate, WayType diff --git a/src/c3nav/routing/route.py b/src/c3nav/routing/route.py index 60a5ecfe..45ed6680 100644 --- a/src/c3nav/routing/route.py +++ b/src/c3nav/routing/route.py @@ -4,7 +4,7 @@ from collections import OrderedDict, deque import numpy as np from django.utils.functional import cached_property -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ def describe_location(location, locations): diff --git a/src/c3nav/settings.py b/src/c3nav/settings.py index 4c07cff3..bfb5c071 100644 --- a/src/c3nav/settings.py +++ b/src/c3nav/settings.py @@ -8,7 +8,7 @@ from contextlib import suppress import sass from django.contrib.messages import constants as messages from django.utils.crypto import get_random_string -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ config = configparser.RawConfigParser() if 'C3NAV_CONFIG' in os.environ: @@ -141,6 +141,7 @@ DATABASES = { 'CONN_MAX_AGE': 0 if db_backend == 'sqlite3' else 120 } } +DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' STATIC_URL = config.get('urls', 'static', fallback='/static/') @@ -407,6 +408,8 @@ MESSAGE_TAGS = { } MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage' +SILENCED_SYSTEM_CHECKS = ['debug_toolbar.W006'] + loglevel = 'DEBUG' if DEBUG else 'INFO' LOGGING = { diff --git a/src/c3nav/site/converters.py b/src/c3nav/site/converters.py new file mode 100644 index 00000000..bf371050 --- /dev/null +++ b/src/c3nav/site/converters.py @@ -0,0 +1,53 @@ +from collections import namedtuple + + +class LocationConverter: + regex = '[a-zA-Z0-9-_.:]+' + + def to_python(self, value): + return value + + def to_url(self, value): + return value + + +class CoordinatesConverter: + regex = r'[a-z0-9-_:]+:-?\d+(\.\d+)?:-?\d+(\.\d+)?' + + def to_python(self, value): + return value + + def to_url(self, value): + return value + + +AtPos = namedtuple('AtPos', ('level', 'x', 'y', 'zoom')) + + +class AtPositionConverter: + regex = r'(@[a-z0-9-_:]+,-?\d+(\.\d+)?,-?\d+(\.\d+)?,-?\d+(\.\d+)?)?' + + def to_python(self, value): + if not value: + return None + value = AtPos(*value.split(',')) + return AtPos(value.level, float(value.x), float(value.y), float(value.zoom)) + + def to_url(self, value): + return ','.join(str(s) for s in value) + + +class ConditionalConverter: + def __init_subclass__(cls, /, name): + cls.path = '%s/' % name + cls.regex = '(%s/)?' % name + + def to_python(self, value): + return value != '' + + def to_url(self, value): + return self.path if value else '' + + +class IsEmbedConverter(ConditionalConverter, name='embed'): + pass diff --git a/src/c3nav/site/forms.py b/src/c3nav/site/forms.py index 7ca1313b..0a779f11 100644 --- a/src/c3nav/site/forms.py +++ b/src/c3nav/site/forms.py @@ -2,7 +2,7 @@ from operator import attrgetter from django.db import transaction from django.forms import Form, ModelChoiceField, ModelForm -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.mapdata.forms import I18nModelFormMixin from c3nav.mapdata.models.locations import Position diff --git a/src/c3nav/site/models.py b/src/c3nav/site/models.py index 6d74245b..e8831f34 100644 --- a/src/c3nav/site/models.py +++ b/src/c3nav/site/models.py @@ -5,7 +5,7 @@ from django.core.cache import cache from django.db import models, transaction from django.db.models import Q from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from c3nav.mapdata.fields import I18nField diff --git a/src/c3nav/site/urls.py b/src/c3nav/site/urls.py index 851c389e..e7c1caf8 100644 --- a/src/c3nav/site/urls.py +++ b/src/c3nav/site/urls.py @@ -1,42 +1,48 @@ -from django.conf.urls import url +from django.urls import path, register_converter +from c3nav.site.converters import LocationConverter, CoordinatesConverter, AtPositionConverter, IsEmbedConverter from c3nav.site.views import (about_view, access_redeem_view, account_view, change_password_view, choose_language, login_view, logout_view, map_index, position_create, position_detail, position_list, position_set, qr_code, register_view, report_create, report_detail, report_list) -slug = r'(?P[a-zA-Z0-9-_.:]+)' -coordinates = r'(?P[a-z0-9-_:]+:-?\d+(\.\d+)?:-?\d+(\.\d+)?)' -slug2 = r'(?P[a-zA-Z0-9-_.:]+)' -details = r'(?P
details/)?' -nearby = r'(?Pnearby/)?' -options = r'(?Poptions/)?' -pos = r'(@(?P[a-z0-9-_:]+),(?P-?\d+(\.\d+)?),(?P-?\d+(\.\d+)?),(?P-?\d+(\.\d+)?))?' -embed = r'(?Pembed/)?' +register_converter(LocationConverter, 'loc') +register_converter(CoordinatesConverter, 'coords') +register_converter(AtPositionConverter, 'at_pos') +register_converter(IsEmbedConverter, 'is_embed') + +embed = '' +pos = '' urlpatterns = [ - url(r'^%s(?P[l])/%s/(%s|%s)%s$' % (embed, slug, details, nearby, pos), map_index, name='site.index'), - url(r'^%s(?P[od])/%s/%s$' % (embed, slug, pos), map_index, name='site.index'), - url(r'^%sr/%s/%s/(%s|%s)%s$' % (embed, slug, slug2, details, options, pos), map_index, name='site.index'), - url(r'^%s(?Pr)/%s$' % (embed, pos), map_index, name='site.index'), - url(r'^%s%s$' % (embed, pos), map_index, name='site.index'), - url(r'^qr/(?P.*)$', qr_code, name='site.qr'), - url(r'^login$', login_view, name='site.login'), - url(r'^logout$', logout_view, name='site.logout'), - url(r'^register$', register_view, name='site.register'), - url(r'^account/$', account_view, name='site.account'), - url(r'^account/change_password$', change_password_view, name='site.account.change_password'), - url(r'^access/(?P[^/]+)$', access_redeem_view, name='site.access.redeem'), - url(r'^lang/$', choose_language, name='site.language'), - url(r'^about/$', about_view, name='site.about'), - url(r'^reports/(?P(open|all))/$', report_list, name='site.report_list'), - url(r'^reports/(?P\d+)/$', report_detail, name='site.report_detail'), - url(r'^reports/(?P\d+)/(?P[^/]+)/$', report_detail, name='site.report_detail'), - url(r'^report/l/%s/$' % coordinates, report_create, name='site.report_create'), - url(r'^report/l/(?P\d+)/$', report_create, name='site.report_create'), - url(r'^report/r/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/$', - report_create, name='site.report_create'), - url(r'^positions/$', position_list, name='site.position_list'), - url(r'^positions/create/$', position_create, name='site.position_create'), - url(r'^positions/(?P\d+)/$', position_detail, name='site.position_detail'), - url(r'^positions/set/%s/$' % coordinates, position_set, name='site.position_set'), + path(f'{embed}l//{pos}', map_index, {'mode': 'l'}, name='site.index', ), + path(f'{embed}l//details/{pos}', map_index, {'mode': 'l', 'details': True}, name='site.index'), + path(f'{embed}l//nearby/{pos}', map_index, {'mode': 'l', 'nearby': True}, name='site.index'), + path(f'{embed}o//{pos}', map_index, {'mode': 'o'}, name='site.index'), + path(f'{embed}d//{pos}', map_index, {'mode': 'd'}, name='site.index'), + path(f'{embed}r/{pos}', map_index, {'mode': 'r'}, name='site.index'), + path(f'{embed}r///{pos}', map_index, {'mode': 'r'}, name='site.index'), + path(f'{embed}r///details{pos}', map_index, {'mode': 'r', 'details': True}, name='site.index'), + path(f'{embed}r///options{pos}', map_index, {'mode': 'r', 'options': True}, name='site.index'), + path(f'{embed}r///options{pos}', map_index, {'mode': 'r', 'options': True}, name='site.index'), + path(f'{embed}{pos}', map_index, name='site.index'), + path('qr/', qr_code, name='site.qr'), + path('login', login_view, name='site.login'), + path('logout', logout_view, name='site.logout'), + path('register', register_view, name='site.register'), + path('account/', account_view, name='site.account'), + path('account/change_password', change_password_view, name='site.account.change_password'), + path('access/', access_redeem_view, name='site.access.redeem'), + path('lang/', choose_language, name='site.language'), + path('about/', about_view, name='site.about'), + path('reports/open/', report_list, {'filter': 'open'}, name='site.report_list'), + path('reports/all/', report_list, {'filter': 'all'}, name='site.report_list'), + path('reports//', report_detail, name='site.report_detail'), + path('reports///', report_detail, name='site.report_detail'), + path('report/l//', report_create, name='site.report_create'), + path('report/l//', report_create, name='site.report_create'), + path('report/r////', report_create, name='site.report_create'), + path('positions/', position_list, name='site.position_list'), + path('positions/create/', position_create, name='site.position_create'), + path('positions//', position_detail, name='site.position_detail'), + path('positions/set//', position_set, name='site.position_set'), ] diff --git a/src/c3nav/site/views.py b/src/c3nav/site/views.py index 6d73edde..fbacd48a 100644 --- a/src/c3nav/site/views.py +++ b/src/c3nav/site/views.py @@ -18,8 +18,8 @@ from django.middleware import csrf from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ -from django.utils.translation import ungettext_lazy +from django.utils.translation import gettext_lazy as _ +from django.utils.translation import ngettext_lazy from django.views.decorators.cache import cache_control, never_cache from django.views.decorators.clickjacking import xframe_options_exempt from django.views.decorators.http import etag @@ -59,8 +59,7 @@ def check_location(location: Optional[str], request) -> Optional[SpecificLocatio return location -def map_index(request, mode=None, slug=None, slug2=None, details=None, options=None, nearby=None, - level=None, x=None, y=None, zoom=None, embed=None): +def map_index(request, mode=None, slug=None, slug2=None, details=None, options=None, nearby=None, pos=None, embed=None): # check for access token access_signed_data = request.GET.get('access') @@ -83,8 +82,8 @@ def map_index(request, mode=None, slug=None, slug2=None, details=None, options=N token.redeem(request.user) token.save() - messages.success(request, ungettext_lazy('Area successfully unlocked.', - 'Areas successfully unlocked.', num_restrictions)) + messages.success(request, ngettext_lazy('Area successfully unlocked.', + 'Areas successfully unlocked.', num_restrictions)) return redirect('site.index') origin = None @@ -115,12 +114,12 @@ def map_index(request, mode=None, slug=None, slug2=None, details=None, options=N levels = levels_by_short_label_for_request(request) - level = levels.get(level, None) if level else None + level = levels.get(pos.level, None) if pos else None if level is not None: state.update({ 'level': level.pk, - 'center': (float(x), float(y)), - 'zoom': float(zoom), + 'center': (pos.x, pos.y), + 'zoom': pos.zoom, }) initial_bounds = settings.INITIAL_BOUNDS @@ -336,15 +335,15 @@ def access_redeem_view(request, token): token.redeem(request.user) token.save() - messages.success(request, ungettext_lazy('Area successfully unlocked.', - 'Areas successfully unlocked.', num_restrictions)) + messages.success(request, ngettext_lazy('Area successfully unlocked.', + 'Areas successfully unlocked.', num_restrictions)) return redirect('site.index') return render(request, 'site/confirm.html', { - 'title': ungettext_lazy('Unlock area', 'Unlock areas', num_restrictions), - 'texts': (ungettext_lazy('You have been invited to unlock the following area:', - 'You have been invited to unlock the following areas:', - num_restrictions), + 'title': ngettext_lazy('Unlock area', 'Unlock areas', num_restrictions), + 'texts': (ngettext_lazy('You have been invited to unlock the following area:', + 'You have been invited to unlock the following areas:', + num_restrictions), ', '.join(str(restriction.title) for restriction in token.restrictions)), }) diff --git a/src/c3nav/urls.py b/src/c3nav/urls.py index 6bbc8fb9..7cfa0274 100644 --- a/src/c3nav/urls.py +++ b/src/c3nav/urls.py @@ -1,7 +1,7 @@ from contextlib import suppress from django.conf import settings -from django.conf.urls import include, url +from django.urls import include, path from django.contrib import admin import c3nav.api.urls @@ -11,16 +11,16 @@ import c3nav.mapdata.urls import c3nav.site.urls urlpatterns = [ - url(r'^editor/', include(c3nav.editor.urls)), - url(r'^api/', include((c3nav.api.urls, 'api'), namespace='api')), - url(r'^map/', include(c3nav.mapdata.urls)), - url(r'^admin/', admin.site.urls), - url(r'^control/', include(c3nav.control.urls)), - url(r'^locales/', include('django.conf.urls.i18n')), - url(r'^', include(c3nav.site.urls)), + path('editor/', include(c3nav.editor.urls)), + path('api/', include((c3nav.api.urls, 'api'), namespace='api')), + path('map/', include(c3nav.mapdata.urls)), + path('admin/', admin.site.urls), + path('control/', include(c3nav.control.urls)), + path('locales/', include('django.conf.urls.i18n')), + path('', include(c3nav.site.urls)), ] if settings.DEBUG: with suppress(ImportError): import debug_toolbar - urlpatterns.insert(0, url(r'^__debug__/', include(debug_toolbar.urls))) + urlpatterns.insert(0, path('__debug__/', include(debug_toolbar.urls))) diff --git a/src/requirements/dev.txt b/src/requirements/dev.txt index c67a3651..f8b316be 100644 --- a/src/requirements/dev.txt +++ b/src/requirements/dev.txt @@ -1,4 +1,4 @@ -flake8==3.7.9 -pycodestyle==2.5.0 +flake8==4.0.1 +pycodestyle==2.8.0 isort django-debug-toolbar diff --git a/src/requirements/opengl.txt b/src/requirements/opengl.txt index 6ec6c7bf..71371bda 100644 --- a/src/requirements/opengl.txt +++ b/src/requirements/opengl.txt @@ -1 +1 @@ -ModernGL==5.5.4 +ModernGL==5.6.4 diff --git a/src/requirements/production.txt b/src/requirements/production.txt index 350aec12..a495a6c4 100644 --- a/src/requirements/production.txt +++ b/src/requirements/production.txt @@ -1,17 +1,17 @@ -Django==2.2.13 -django-bootstrap3==12.0.0 -django-compressor==2.3 +Django==4.0.3 +django-bootstrap3==21.2 +django-compressor==3.1 csscompressor==0.9.5 -djangorestframework==3.10.3 -django-filter==2.2.0 -shapely==1.6.4.post2 -pybind11==2.4.3 -MeshPy==2018.2.1 +djangorestframework==3.13.1 +django-filter==21.1 +shapely==1.8.1.post1 +pybind11==2.9.2 +MeshPy==2020.1 # rtree==0.9.1 -celery==4.3.0 -requests==2.22.0 -Pillow==6.2.1 -qrcode==6.1 -matplotlib==3.1.2 -scipy==1.3.3 -django_libsass==0.7 +celery==5.2.3 +requests==2.27.1 +Pillow==9.1.0 +qrcode==7.3.1 +matplotlib==3.5.1 +scipy==1.8.0 +django_libsass==0.9 diff --git a/src/requirements/redis.txt b/src/requirements/redis.txt index f9b781eb..c4fee00f 100644 --- a/src/requirements/redis.txt +++ b/src/requirements/redis.txt @@ -1,2 +1,2 @@ -django-redis==4.10.0 -redis==3.3.11 +django-redis==5.2.0 +redis==4.2.1 diff --git a/src/requirements/rsvg.txt b/src/requirements/rsvg.txt index 1fa13d3a..b4b199da 100644 --- a/src/requirements/rsvg.txt +++ b/src/requirements/rsvg.txt @@ -1,2 +1,2 @@ pgi==0.0.11.2 -cairocffi==1.1.0 +cairocffi==1.3.0 diff --git a/src/requirements/sentry.txt b/src/requirements/sentry.txt index fb470dba..c283bd22 100644 --- a/src/requirements/sentry.txt +++ b/src/requirements/sentry.txt @@ -1 +1 @@ -sentry-sdk==0.13.5 +sentry-sdk==1.5.8