[style] Format the code

This commit is contained in:
Alexis Métaireau 2023-11-23 18:04:23 +01:00
parent 72b0bc44ad
commit aff0181636
38 changed files with 446 additions and 252 deletions

View file

@ -3,10 +3,7 @@ import os
import sys import sys
if __name__ == "__main__": if __name__ == "__main__":
os.environ.setdefault( os.environ.setdefault("DJANGO_SETTINGS_MODULE", "umap.settings")
"DJANGO_SETTINGS_MODULE",
"umap.settings"
)
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line

View file

@ -1,10 +1,14 @@
from django.contrib.gis import admin from django.contrib.gis import admin
from .models import Map, DataLayer, Pictogram, TileLayer, Licence
from .models import DataLayer, Licence, Map, Pictogram, TileLayer
class TileLayerAdmin(admin.ModelAdmin): class TileLayerAdmin(admin.ModelAdmin):
list_display = ('name', 'rank', ) list_display = (
list_editable = ('rank', ) "name",
"rank",
)
list_editable = ("rank",)
class MapAdmin(admin.GISModelAdmin): class MapAdmin(admin.GISModelAdmin):

View file

@ -1,11 +1,9 @@
from agnocomplete.core import AgnocompleteModel
from agnocomplete.register import register
from django.conf import settings from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from agnocomplete.register import register
from agnocomplete.core import AgnocompleteModel
@register @register
class AutocompleteUser(AgnocompleteModel): class AutocompleteUser(AgnocompleteModel):
model = get_user_model() model = get_user_model()
@ -13,5 +11,5 @@ class AutocompleteUser(AgnocompleteModel):
def item(self, current_item): def item(self, current_item):
data = super().item(current_item) data = super().item(current_item)
data['url'] = current_item.get_url() data["url"] = current_item.get_url()
return data return data

View file

@ -5,12 +5,9 @@ from django.core import management
def main(): def main():
os.environ.setdefault( os.environ.setdefault("DJANGO_SETTINGS_MODULE", "umap.settings")
"DJANGO_SETTINGS_MODULE",
"umap.settings"
)
management.execute_from_command_line() management.execute_from_command_line()
if __name__ == '__main__': if __name__ == "__main__":
main() main()

View file

@ -1,13 +1,12 @@
from functools import wraps from functools import wraps
from django.urls import reverse_lazy
from django.shortcuts import get_object_or_404
from django.http import HttpResponseForbidden
from django.conf import settings from django.conf import settings
from django.http import HttpResponseForbidden
from django.shortcuts import get_object_or_404
from django.urls import reverse_lazy
from .views import simple_json_response
from .models import Map from .models import Map
from .views import simple_json_response
LOGIN_URL = getattr(settings, "LOGIN_URL", "login") LOGIN_URL = getattr(settings, "LOGIN_URL", "login")
LOGIN_URL = reverse_lazy(LOGIN_URL) if not LOGIN_URL.startswith("/") else LOGIN_URL LOGIN_URL = reverse_lazy(LOGIN_URL) if not LOGIN_URL.startswith("/") else LOGIN_URL

View file

@ -1,12 +1,12 @@
from django import forms from django import forms
from django.contrib.gis.geos import Point
from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy as _
from django.template.defaultfilters import slugify
from django.conf import settings from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.gis.geos import Point
from django.forms.utils import ErrorList from django.forms.utils import ErrorList
from django.template.defaultfilters import slugify
from django.utils.translation import gettext_lazy as _
from .models import Map, DataLayer from .models import DataLayer, Map
DEFAULT_LATITUDE = ( DEFAULT_LATITUDE = (
settings.LEAFLET_LATITUDE if hasattr(settings, "LEAFLET_LATITUDE") else 51 settings.LEAFLET_LATITUDE if hasattr(settings, "LEAFLET_LATITUDE") else 51

View file

@ -1,24 +1,23 @@
from pathlib import Path from pathlib import Path
from django.core.management.base import BaseCommand
from django.conf import settings from django.conf import settings
from django.core.management.base import BaseCommand
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.utils.translation import to_locale from django.utils.translation import to_locale
ROOT = Path(settings.PROJECT_DIR) / 'static/umap/locale/' ROOT = Path(settings.PROJECT_DIR) / "static/umap/locale/"
class Command(BaseCommand): class Command(BaseCommand):
def handle(self, *args, **options): def handle(self, *args, **options):
self.verbosity = options['verbosity'] self.verbosity = options["verbosity"]
for code, name in settings.LANGUAGES: for code, name in settings.LANGUAGES:
code = to_locale(code) code = to_locale(code)
if self.verbosity > 0: if self.verbosity > 0:
print("Processing", name) print("Processing", name)
path = ROOT / '{code}.json'.format(code=code) path = ROOT / "{code}.json".format(code=code)
if not path.exists(): if not path.exists():
print(path, 'does not exist.', 'Skipping') print(path, "does not exist.", "Skipping")
else: else:
with path.open(encoding="utf-8") as f: with path.open(encoding="utf-8") as f:
if self.verbosity > 1: if self.verbosity > 1:
@ -26,12 +25,11 @@ class Command(BaseCommand):
self.render(code, f.read()) self.render(code, f.read())
def render(self, code, json): def render(self, code, json):
path = ROOT / '{code}.js'.format(code=code) path = ROOT / "{code}.js".format(code=code)
with path.open("w", encoding="utf-8") as f: with path.open("w", encoding="utf-8") as f:
content = render_to_string('umap/locale.js', { content = render_to_string(
"locale": json, "umap/locale.js", {"locale": json, "locale_code": code}
"locale_code": code )
})
if self.verbosity > 1: if self.verbosity > 1:
print("Exporting to", path) print("Exporting to", path)
f.write(content) f.write(content)

View file

@ -59,7 +59,7 @@ class Command(BaseCommand):
else: else:
picto = Pictogram() picto = Pictogram()
picto.name = name picto.name = name
if (path.name != self.path.name): # Subfolders only if path.name != self.path.name: # Subfolders only
picto.category = path.name picto.category = path.name
picto.attribution = self.attribution picto.attribution = self.attribution
with (path / filename).open("rb") as f: with (path / filename).open("rb") as f:

View file

@ -2,7 +2,9 @@ from django.db.models import Manager
class PublicManager(Manager): class PublicManager(Manager):
def get_queryset(self): def get_queryset(self):
return super(PublicManager, self).get_queryset().filter( return (
share_status=self.model.PUBLIC) super(PublicManager, self)
.get_queryset()
.filter(share_status=self.model.PUBLIC)
)

View file

@ -5,13 +5,12 @@ from django.utils.translation import gettext as _
def readonly_middleware(get_response): def readonly_middleware(get_response):
if not settings.UMAP_READONLY: if not settings.UMAP_READONLY:
raise MiddlewareNotUsed raise MiddlewareNotUsed
def middleware(request): def middleware(request):
if request.method not in ['GET', 'OPTIONS']: if request.method not in ["GET", "OPTIONS"]:
return HttpResponseForbidden(_('Site is readonly for maintenance')) return HttpResponseForbidden(_("Site is readonly for maintenance"))
return get_response(request) return get_response(request)

View file

@ -1,15 +1,15 @@
# Generated by Django 2.0.5 on 2018-05-19 09:27 # Generated by Django 2.0.5 on 2018-05-19 09:27
from django.conf import settings
import django.contrib.gis.db.models.fields import django.contrib.gis.db.models.fields
from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
import umap.fields import umap.fields
import umap.models import umap.models
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
@ -18,90 +18,238 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='DataLayer', name="DataLayer",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=200, verbose_name='name')), "id",
('description', models.TextField(blank=True, null=True, verbose_name='description')), models.AutoField(
('geojson', models.FileField(blank=True, null=True, upload_to=umap.models.upload_to)), auto_created=True,
('display_on_load', models.BooleanField(default=False, help_text='Display this layer on load.', verbose_name='display on load')), primary_key=True,
('rank', models.SmallIntegerField(default=0)), serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=200, verbose_name="name")),
(
"description",
models.TextField(blank=True, null=True, verbose_name="description"),
),
(
"geojson",
models.FileField(
blank=True, null=True, upload_to=umap.models.upload_to
),
),
(
"display_on_load",
models.BooleanField(
default=False,
help_text="Display this layer on load.",
verbose_name="display on load",
),
),
("rank", models.SmallIntegerField(default=0)),
], ],
options={ options={
'ordering': ('rank',), "ordering": ("rank",),
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='Licence', name="Licence",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=200, verbose_name='name')), "id",
('details', models.URLField(help_text='Link to a page where the licence is detailed.', verbose_name='details')), models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=200, verbose_name="name")),
(
"details",
models.URLField(
help_text="Link to a page where the licence is detailed.",
verbose_name="details",
),
),
], ],
options={ options={
'ordering': ('name',), "ordering": ("name",),
'abstract': False, "abstract": False,
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='Map', name="Map",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=200, verbose_name='name')), "id",
('slug', models.SlugField()), models.AutoField(
('description', models.TextField(blank=True, null=True, verbose_name='description')), auto_created=True,
('center', django.contrib.gis.db.models.fields.PointField(geography=True, srid=4326, verbose_name='center')), primary_key=True,
('zoom', models.IntegerField(default=7, verbose_name='zoom')), serialize=False,
('locate', models.BooleanField(default=False, help_text='Locate user on load?', verbose_name='locate')), verbose_name="ID",
('modified_at', models.DateTimeField(auto_now=True)), ),
('edit_status', models.SmallIntegerField(choices=[(1, 'Everyone can edit'), (2, 'Only editors can edit'), (3, 'Only owner can edit')], default=3, verbose_name='edit status')), ),
('share_status', models.SmallIntegerField(choices=[(1, 'everyone (public)'), (2, 'anyone with link'), (3, 'editors only')], default=1, verbose_name='share status')), ("name", models.CharField(max_length=200, verbose_name="name")),
('settings', umap.fields.DictField(blank=True, null=True, verbose_name='settings')), ("slug", models.SlugField()),
('editors', models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='editors')), (
('licence', models.ForeignKey(default=umap.models.get_default_licence, help_text='Choose the map licence.', on_delete=django.db.models.deletion.SET_DEFAULT, to='umap.Licence', verbose_name='licence')), "description",
('owner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='owned_maps', to=settings.AUTH_USER_MODEL, verbose_name='owner')), models.TextField(blank=True, null=True, verbose_name="description"),
),
(
"center",
django.contrib.gis.db.models.fields.PointField(
geography=True, srid=4326, verbose_name="center"
),
),
("zoom", models.IntegerField(default=7, verbose_name="zoom")),
(
"locate",
models.BooleanField(
default=False,
help_text="Locate user on load?",
verbose_name="locate",
),
),
("modified_at", models.DateTimeField(auto_now=True)),
(
"edit_status",
models.SmallIntegerField(
choices=[
(1, "Everyone can edit"),
(2, "Only editors can edit"),
(3, "Only owner can edit"),
],
default=3,
verbose_name="edit status",
),
),
(
"share_status",
models.SmallIntegerField(
choices=[
(1, "everyone (public)"),
(2, "anyone with link"),
(3, "editors only"),
],
default=1,
verbose_name="share status",
),
),
(
"settings",
umap.fields.DictField(
blank=True, null=True, verbose_name="settings"
),
),
(
"editors",
models.ManyToManyField(
blank=True, to=settings.AUTH_USER_MODEL, verbose_name="editors"
),
),
(
"licence",
models.ForeignKey(
default=umap.models.get_default_licence,
help_text="Choose the map licence.",
on_delete=django.db.models.deletion.SET_DEFAULT,
to="umap.Licence",
verbose_name="licence",
),
),
(
"owner",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="owned_maps",
to=settings.AUTH_USER_MODEL,
verbose_name="owner",
),
),
], ],
options={ options={
'ordering': ('name',), "ordering": ("name",),
'abstract': False, "abstract": False,
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='Pictogram', name="Pictogram",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=200, verbose_name='name')), "id",
('attribution', models.CharField(max_length=300)), models.AutoField(
('pictogram', models.ImageField(upload_to='pictogram')), auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=200, verbose_name="name")),
("attribution", models.CharField(max_length=300)),
("pictogram", models.ImageField(upload_to="pictogram")),
], ],
options={ options={
'ordering': ('name',), "ordering": ("name",),
'abstract': False, "abstract": False,
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='TileLayer', name="TileLayer",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=200, verbose_name='name')), "id",
('url_template', models.CharField(help_text='URL template using OSM tile format', max_length=200)), models.AutoField(
('minZoom', models.IntegerField(default=0)), auto_created=True,
('maxZoom', models.IntegerField(default=18)), primary_key=True,
('attribution', models.CharField(max_length=300)), serialize=False,
('rank', models.SmallIntegerField(blank=True, help_text='Order of the tilelayers in the edit box', null=True)), verbose_name="ID",
),
),
("name", models.CharField(max_length=200, verbose_name="name")),
(
"url_template",
models.CharField(
help_text="URL template using OSM tile format", max_length=200
),
),
("minZoom", models.IntegerField(default=0)),
("maxZoom", models.IntegerField(default=18)),
("attribution", models.CharField(max_length=300)),
(
"rank",
models.SmallIntegerField(
blank=True,
help_text="Order of the tilelayers in the edit box",
null=True,
),
),
], ],
options={ options={
'ordering': ('rank', 'name'), "ordering": ("rank", "name"),
}, },
), ),
migrations.AddField( migrations.AddField(
model_name='map', model_name="map",
name='tilelayer', name="tilelayer",
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='maps', to='umap.TileLayer', verbose_name='background'), field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.PROTECT,
related_name="maps",
to="umap.TileLayer",
verbose_name="background",
),
), ),
migrations.AddField( migrations.AddField(
model_name='datalayer', model_name="datalayer",
name='map', name="map",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='umap.Map'), field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="umap.Map"
),
), ),
] ]

View file

@ -4,15 +4,14 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('umap', '0001_initial'), ("umap", "0001_initial"),
] ]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='tilelayer', model_name="tilelayer",
name='tms', name="tms",
field=models.BooleanField(default=False), field=models.BooleanField(default=False),
), ),
] ]

View file

@ -5,22 +5,26 @@ from django.db import migrations
def add_tilelayer(apps, *args): def add_tilelayer(apps, *args):
TileLayer = apps.get_model('umap', 'TileLayer') TileLayer = apps.get_model("umap", "TileLayer")
if TileLayer.objects.count(): if TileLayer.objects.count():
return return
TileLayer( TileLayer(
name='Positron', name="Positron",
url_template=('https://cartodb-basemaps-{s}.global.ssl.fastly.net/' url_template=(
'light_all/{z}/{x}/{y}.png'), "https://cartodb-basemaps-{s}.global.ssl.fastly.net/"
attribution=('© [[http://www.openstreetmap.org/copyright|' "light_all/{z}/{x}/{y}.png"
'OpenStreetMap]] contributors, © ' ),
'[[https://carto.com/attributions|CARTO]]')).save() attribution=(
"© [[http://www.openstreetmap.org/copyright|"
"OpenStreetMap]] contributors, © "
"[[https://carto.com/attributions|CARTO]]"
),
).save()
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('umap', '0002_tilelayer_tms'), ("umap", "0002_tilelayer_tms"),
] ]
operations = [ operations = [

View file

@ -5,18 +5,15 @@ from django.db import migrations
def add_licence(apps, *args): def add_licence(apps, *args):
Licence = apps.get_model('umap', 'Licence') Licence = apps.get_model("umap", "Licence")
if Licence.objects.count(): if Licence.objects.count():
return return
Licence( Licence(name="ODbL", details="http://opendatacommons.org/licenses/odbl/").save()
name='ODbL',
details='http://opendatacommons.org/licenses/odbl/').save()
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('umap', '0003_add_tilelayer'), ("umap", "0003_add_tilelayer"),
] ]
operations = [ operations = [

View file

@ -4,14 +4,13 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('umap', '0004_add_licence'), ("umap", "0004_add_licence"),
] ]
operations = [ operations = [
migrations.RemoveField( migrations.RemoveField(
model_name='map', model_name="map",
name='tilelayer', name="tilelayer",
), ),
] ]

View file

@ -5,15 +5,16 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('umap', '0005_remove_map_tilelayer'), ("umap", "0005_remove_map_tilelayer"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='map', model_name="map",
name='settings', name="settings",
field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=dict, null=True, verbose_name='settings'), field=django.contrib.postgres.fields.jsonb.JSONField(
blank=True, default=dict, null=True, verbose_name="settings"
),
), ),
] ]

View file

@ -4,15 +4,23 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('umap', '0006_auto_20190407_0719'), ("umap", "0006_auto_20190407_0719"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='map', model_name="map",
name='share_status', name="share_status",
field=models.SmallIntegerField(choices=[(1, 'everyone (public)'), (2, 'anyone with link'), (3, 'editors only'), (9, 'blocked')], default=1, verbose_name='share status'), field=models.SmallIntegerField(
choices=[
(1, "everyone (public)"),
(2, "anyone with link"),
(3, "editors only"),
(9, "blocked"),
],
default=1,
verbose_name="share status",
),
), ),
] ]

View file

@ -4,7 +4,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
("umap", "0007_auto_20190416_1757"), ("umap", "0007_auto_20190416_1757"),
] ]

View file

@ -1,25 +1,44 @@
# Generated by Django 4.1.7 on 2023-05-05 18:02 # Generated by Django 4.1.7 on 2023-05-05 18:02
import django.db.models.deletion
from django.conf import settings from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('umap', '0008_alter_map_settings'), ("umap", "0008_alter_map_settings"),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Star', name="Star",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('at', models.DateTimeField(auto_now=True)), "id",
('by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='stars', to=settings.AUTH_USER_MODEL)), models.AutoField(
('map', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='umap.map')), auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("at", models.DateTimeField(auto_now=True)),
(
"by",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="stars",
to=settings.AUTH_USER_MODEL,
),
),
(
"map",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="umap.map"
),
),
], ],
), ),
] ]

View file

@ -4,20 +4,32 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('umap', '0009_star'), ("umap", "0009_star"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='map', model_name="map",
name='edit_status', name="edit_status",
field=models.SmallIntegerField(choices=[(1, 'Everyone'), (2, 'Editors only'), (3, 'Owner only')], default=3, verbose_name='edit status'), field=models.SmallIntegerField(
choices=[(1, "Everyone"), (2, "Editors only"), (3, "Owner only")],
default=3,
verbose_name="edit status",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='map', model_name="map",
name='share_status', name="share_status",
field=models.SmallIntegerField(choices=[(1, 'Everyone (public)'), (2, 'Anyone with link'), (3, 'Editors only'), (9, 'Blocked')], default=1, verbose_name='share status'), field=models.SmallIntegerField(
choices=[
(1, "Everyone (public)"),
(2, "Anyone with link"),
(3, "Editors only"),
(9, "Blocked"),
],
default=1,
verbose_name="share status",
),
), ),
] ]

View file

@ -1,24 +1,37 @@
# Generated by Django 4.2.2 on 2023-08-07 06:07 # Generated by Django 4.2.2 on 2023-08-07 06:07
from django.db import migrations, models from django.db import migrations, models
import umap.models import umap.models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('umap', '0010_alter_map_edit_status_alter_map_share_status'), ("umap", "0010_alter_map_edit_status_alter_map_share_status"),
] ]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='map', model_name="map",
name='edit_status', name="edit_status",
field=models.SmallIntegerField(choices=[(1, 'Everyone'), (2, 'Editors only'), (3, 'Owner only')], default=umap.models.get_default_edit_status, verbose_name='edit status'), field=models.SmallIntegerField(
choices=[(1, "Everyone"), (2, "Editors only"), (3, "Owner only")],
default=umap.models.get_default_edit_status,
verbose_name="edit status",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='map', model_name="map",
name='share_status', name="share_status",
field=models.SmallIntegerField(choices=[(1, 'Everyone (public)'), (2, 'Anyone with link'), (3, 'Editors only'), (9, 'Blocked')], default=umap.models.get_default_share_status, verbose_name='share status'), field=models.SmallIntegerField(
choices=[
(1, "Everyone (public)"),
(2, "Anyone with link"),
(3, "Editors only"),
(9, "Blocked"),
],
default=umap.models.get_default_share_status,
verbose_name="share status",
),
), ),
] ]

View file

@ -1,7 +1,7 @@
# Generated by Django 4.2.2 on 2023-09-27 08:50 # Generated by Django 4.2.2 on 2023-09-27 08:50
from django.db import migrations, models
import django.utils.timezone import django.utils.timezone
from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):

View file

@ -1,14 +1,14 @@
import os import os
import time import time
from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.gis.db import models from django.contrib.gis.db import models
from django.conf import settings from django.core.files.base import File
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from django.core.signing import Signer from django.core.signing import Signer
from django.template.defaultfilters import slugify from django.template.defaultfilters import slugify
from django.core.files.base import File from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from .managers import PublicManager from .managers import PublicManager
@ -380,7 +380,7 @@ class DataLayer(NamedModel):
} }
obj["id"] = self.pk obj["id"] = self.pk
obj["permissions"] = {"edit_status": self.edit_status} obj["permissions"] = {"edit_status": self.edit_status}
obj["editMode"] = "advanced" if self.can_edit(user, request) else 'disabled' obj["editMode"] = "advanced" if self.can_edit(user, request) else "disabled"
return obj return obj
def clone(self, map_inst=None): def clone(self, map_inst=None):
@ -436,7 +436,7 @@ class DataLayer(NamedModel):
root = self.storage_root() root = self.storage_root()
names = self.geojson.storage.listdir(root)[1] names = self.geojson.storage.listdir(root)[1]
for name in names: for name in names:
if name.startswith(f'{self.pk}_') and name.endswith(".gz"): if name.startswith(f"{self.pk}_") and name.endswith(".gz"):
self.geojson.storage.delete(os.path.join(root, name)) self.geojson.storage.delete(os.path.join(root, name))
def can_edit(self, user=None, request=None): def can_edit(self, user=None, request=None):

View file

@ -4,7 +4,6 @@ from email.utils import parseaddr
import environ import environ
from django.conf.locale import LANG_INFO from django.conf.locale import LANG_INFO
from django.template.defaultfilters import slugify
env = environ.Env() env = environ.Env()
@ -244,9 +243,7 @@ UMAP_MAPS_PER_PAGE = 5
UMAP_MAPS_PER_SEARCH = 25 UMAP_MAPS_PER_SEARCH = 25
UMAP_MAPS_PER_PAGE_OWNER = 10 UMAP_MAPS_PER_PAGE_OWNER = 10
UMAP_SEARCH_CONFIGURATION = "simple" UMAP_SEARCH_CONFIGURATION = "simple"
UMAP_FEEDBACK_LINK = ( UMAP_FEEDBACK_LINK = "https://wiki.openstreetmap.org/wiki/UMap#Feedback_and_help"
"https://wiki.openstreetmap.org/wiki/UMap#Feedback_and_help" # noqa
)
USER_MAPS_URL = "user_maps" USER_MAPS_URL = "user_maps"
DATABASES = {"default": env.db(default="postgis://localhost:5432/umap")} DATABASES = {"default": env.db(default="postgis://localhost:5432/umap")}
UMAP_DEFAULT_SHARE_STATUS = None UMAP_DEFAULT_SHARE_STATUS = None

View file

@ -3,7 +3,7 @@
{% block maincontent %} {% block maincontent %}
<div class="col wide"> <div class="col wide">
<h2 class="section tabs"> <h2 class="section tabs">
<a href="{% url 'user_dashboard' %}">{% trans "My Dashboard" %}</a> | {% trans "My Profile" %} <a href="{% url "user_dashboard" %}">{% trans "My Dashboard" %}</a> | {% trans "My Profile" %}
</h2> </h2>
</div> </div>
<div class="wrapper"> <div class="wrapper">
@ -16,7 +16,7 @@
<form id="user_form" method="post"> <form id="user_form" method="post">
{% csrf_token %} {% csrf_token %}
{{ form }} {{ form }}
<input type="submit" value="{% trans 'Save' %}" /> <input type="submit" value="{% trans "Save" %}" />
</form> </form>
</div> </div>
{% if backends.backends|length %} {% if backends.backends|length %}

View file

@ -16,9 +16,15 @@
<meta name="viewport" <meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
{# See https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs #} {# See https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs #}
<link rel="icon" href="{{ STATIC_URL }}umap/favicons/favicon.ico" sizes="32x32"> <link rel="icon"
<link rel="icon" href="{{ STATIC_URL }}umap/favicons/icon.svg" type="image/svg+xml"> href="{{ STATIC_URL }}umap/favicons/favicon.ico"
<link rel="apple-touch-icon" href="{{ STATIC_URL }}umap/favicons/apple-touch-icon.png"><!-- 180×180 --> sizes="32x32">
<link rel="icon"
href="{{ STATIC_URL }}umap/favicons/icon.svg"
type="image/svg+xml">
<link rel="apple-touch-icon"
href="{{ STATIC_URL }}umap/favicons/apple-touch-icon.png">
<!-- 180×180 -->
<link rel="manifest" href="/manifest.webmanifest"> <link rel="manifest" href="/manifest.webmanifest">
</head> </head>
<body class="{% block body_class %}{% endblock body_class %}"> <body class="{% block body_class %}{% endblock body_class %}">

View file

@ -10,53 +10,50 @@ from ..views import _urls_for_js
register = template.Library() register = template.Library()
@register.inclusion_tag('umap/css.html') @register.inclusion_tag("umap/css.html")
def umap_css(): def umap_css():
return { return {"STATIC_URL": settings.STATIC_URL}
"STATIC_URL": settings.STATIC_URL
}
@register.inclusion_tag('umap/js.html') @register.inclusion_tag("umap/js.html")
def umap_js(locale=None): def umap_js(locale=None):
return { return {"STATIC_URL": settings.STATIC_URL, "locale": locale}
"STATIC_URL": settings.STATIC_URL,
"locale": locale
}
@register.inclusion_tag('umap/map_fragment.html') @register.inclusion_tag("umap/map_fragment.html")
def map_fragment(map_instance, **kwargs): def map_fragment(map_instance, **kwargs):
layers = DataLayer.objects.filter(map=map_instance) layers = DataLayer.objects.filter(map=map_instance)
datalayer_data = [c.metadata() for c in layers] datalayer_data = [c.metadata() for c in layers]
map_settings = map_instance.settings map_settings = map_instance.settings
if "properties" not in map_settings: if "properties" not in map_settings:
map_settings['properties'] = {} map_settings["properties"] = {}
map_settings['properties'].update({ map_settings["properties"].update(
'tilelayers': [TileLayer.get_default().json], {
'datalayers': datalayer_data, "tilelayers": [TileLayer.get_default().json],
'urls': _urls_for_js(), "datalayers": datalayer_data,
'STATIC_URL': settings.STATIC_URL, "urls": _urls_for_js(),
"editMode": 'disabled', "STATIC_URL": settings.STATIC_URL,
'hash': False, "editMode": "disabled",
'attributionControl': False, "hash": False,
'scrollWheelZoom': False, "attributionControl": False,
'umapAttributionControl': False, "scrollWheelZoom": False,
'noControl': True, "umapAttributionControl": False,
'umap_id': map_instance.pk, "noControl": True,
'onLoadPanel': "none", "umap_id": map_instance.pk,
'captionBar': False, "onLoadPanel": "none",
'default_iconUrl': "%sumap/img/marker.png" % settings.STATIC_URL, "captionBar": False,
'slideshow': {} "default_iconUrl": "%sumap/img/marker.png" % settings.STATIC_URL,
}) "slideshow": {},
map_settings['properties'].update(kwargs) }
prefix = kwargs.pop('prefix', None) or 'map' )
page = kwargs.pop('page', None) or '' map_settings["properties"].update(kwargs)
prefix = kwargs.pop("prefix", None) or "map"
page = kwargs.pop("page", None) or ""
unique_id = prefix + str(page) + "_" + str(map_instance.pk) unique_id = prefix + str(page) + "_" + str(map_instance.pk)
return { return {
"map_settings": json.dumps(map_settings), "map_settings": json.dumps(map_settings),
"map": map_instance, "map": map_instance,
"unique_id": unique_id "unique_id": unique_id,
} }
@ -73,7 +70,7 @@ def tilelayer_preview(tilelayer):
@register.filter @register.filter
def notag(s): def notag(s):
return s.replace('<', '&lt;') return s.replace("<", "&lt;")
@register.simple_tag(takes_context=True) @register.simple_tag(takes_context=True)
@ -86,5 +83,6 @@ def paginate_querystring(context, page):
@register.filter @register.filter
def ipdb(what): def ipdb(what):
import ipdb import ipdb
ipdb.set_trace() ipdb.set_trace()
return '' return ""

View file

@ -1,5 +1,5 @@
import json
import copy import copy
import json
import factory import factory
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model

View file

@ -77,4 +77,3 @@ def datalayer(map):
@pytest.fixture @pytest.fixture
def tilelayer(): def tilelayer():
return TileLayerFactory() return TileLayerFactory()

View file

@ -1,8 +1,8 @@
from pathlib import Path from pathlib import Path
import pytest import pytest
from playwright.sync_api import expect
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from playwright.sync_api import expect
from umap.models import Map, Pictogram from umap.models import Map, Pictogram

View file

@ -1,8 +1,8 @@
from pathlib import Path from pathlib import Path
import pytest import pytest
from playwright.sync_api import expect
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from playwright.sync_api import expect
from umap.models import Map, Pictogram from umap.models import Map, Pictogram

View file

@ -3,9 +3,10 @@ import os
import pytest import pytest
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from .base import DataLayerFactory, MapFactory
from umap.models import DataLayer, Map from umap.models import DataLayer, Map
from .base import DataLayerFactory, MapFactory
pytestmark = pytest.mark.django_db pytestmark = pytest.mark.django_db
@ -63,13 +64,13 @@ def test_should_remove_old_versions_on_save(datalayer, map, settings):
settings.UMAP_KEEP_VERSIONS = 3 settings.UMAP_KEEP_VERSIONS = 3
root = datalayer.storage_root() root = datalayer.storage_root()
before = len(datalayer.geojson.storage.listdir(root)[1]) before = len(datalayer.geojson.storage.listdir(root)[1])
newer = f'{root}/{datalayer.pk}_1440924889.geojson' newer = f"{root}/{datalayer.pk}_1440924889.geojson"
medium = f'{root}/{datalayer.pk}_1440923687.geojson' medium = f"{root}/{datalayer.pk}_1440923687.geojson"
older = f'{root}/{datalayer.pk}_1440918637.geojson' older = f"{root}/{datalayer.pk}_1440918637.geojson"
other = f'{root}/123456_1440918637.geojson' other = f"{root}/123456_1440918637.geojson"
for path in [medium, newer, older, other]: for path in [medium, newer, older, other]:
datalayer.geojson.storage.save(path, ContentFile("{}")) datalayer.geojson.storage.save(path, ContentFile("{}"))
datalayer.geojson.storage.save(path + '.gz', ContentFile("{}")) datalayer.geojson.storage.save(path + ".gz", ContentFile("{}"))
assert len(datalayer.geojson.storage.listdir(root)[1]) == 8 + before assert len(datalayer.geojson.storage.listdir(root)[1]) == 8 + before
datalayer.save() datalayer.save()
files = datalayer.geojson.storage.listdir(root)[1] files = datalayer.geojson.storage.listdir(root)[1]

View file

@ -50,11 +50,13 @@ def test_editors_can_edit_if_status_editors(map, user):
assert map.can_edit(user) assert map.can_edit(user)
def test_logged_in_user_should_be_allowed_for_anonymous_map_with_anonymous_edit_status(map, user, rf): # noqa def test_logged_in_user_should_be_allowed_for_anonymous_map_with_anonymous_edit_status(
map, user, rf
): # noqa
map.owner = None map.owner = None
map.edit_status = map.ANONYMOUS map.edit_status = map.ANONYMOUS
map.save() map.save()
url = reverse('map_update', kwargs={'map_id': map.pk}) url = reverse("map_update", kwargs={"map_id": map.pk})
request = rf.get(url) request = rf.get(url)
request.user = user request.user = user
assert map.can_edit(user, request) assert map.can_edit(user, request)
@ -70,7 +72,7 @@ def test_anonymous_user_should_not_be_allowed_for_anonymous_map(map, user, rf):
def test_clone_should_return_new_instance(map, user): def test_clone_should_return_new_instance(map, user):
clone = map.clone() clone = map.clone()
assert map.pk != clone.pk assert map.pk != clone.pk
assert u"Clone of " + map.name == clone.name assert "Clone of " + map.name == clone.name
assert map.settings == clone.settings assert map.settings == clone.settings
assert map.center == clone.center assert map.center == clone.center
assert map.zoom == clone.zoom assert map.zoom == clone.zoom
@ -108,8 +110,7 @@ def test_clone_should_clone_datalayers_and_features_too(map, user, datalayer):
def test_publicmanager_should_get_only_public_maps(map, user, licence): def test_publicmanager_should_get_only_public_maps(map, user, licence):
map.share_status = map.PUBLIC map.share_status = map.PUBLIC
open_map = MapFactory(owner=user, licence=licence, share_status=Map.OPEN) open_map = MapFactory(owner=user, licence=licence, share_status=Map.OPEN)
private_map = MapFactory(owner=user, licence=licence, private_map = MapFactory(owner=user, licence=licence, share_status=Map.PRIVATE)
share_status=Map.PRIVATE)
assert map in Map.public.all() assert map in Map.public.all()
assert open_map not in Map.public.all() assert open_map not in Map.public.all()
assert private_map not in Map.public.all() assert private_map not in Map.public.all()

View file

@ -3,8 +3,8 @@ import json
import pytest import pytest
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.core import mail from django.core import mail
from django.urls import reverse
from django.core.signing import Signer from django.core.signing import Signer
from django.urls import reverse
from umap.models import DataLayer, Map, Star from umap.models import DataLayer, Map, Star
@ -275,9 +275,7 @@ def test_owner_cannot_access_map_with_share_status_blocked(client, map):
assert response.status_code == 403 assert response.status_code == 403
def test_non_editor_cannot_access_map_if_share_status_private( def test_non_editor_cannot_access_map_if_share_status_private(client, map, user): # noqa
client, map, user
): # noqa
url = reverse("map", args=(map.slug, map.pk)) url = reverse("map", args=(map.slug, map.pk))
map.share_status = map.PRIVATE map.share_status = map.PRIVATE
map.save() map.save()
@ -355,9 +353,7 @@ def test_anonymous_update_without_cookie_fails(client, anonymap, post_data): #
@pytest.mark.usefixtures("allow_anonymous") @pytest.mark.usefixtures("allow_anonymous")
def test_anonymous_update_with_cookie_should_work( def test_anonymous_update_with_cookie_should_work(cookieclient, anonymap, post_data): # noqa
cookieclient, anonymap, post_data
): # noqa
url = reverse("map_update", kwargs={"map_id": anonymap.pk}) url = reverse("map_update", kwargs={"map_id": anonymap.pk})
# POST only mendatory fields # POST only mendatory fields
name = "new map name" name = "new map name"
@ -438,9 +434,7 @@ def test_clone_anonymous_map_should_not_be_possible_if_user_is_not_allowed(
@pytest.mark.usefixtures("allow_anonymous") @pytest.mark.usefixtures("allow_anonymous")
def test_clone_map_should_be_possible_if_edit_status_is_anonymous( def test_clone_map_should_be_possible_if_edit_status_is_anonymous(client, anonymap): # noqa
client, anonymap
): # noqa
assert Map.objects.count() == 1 assert Map.objects.count() == 1
url = reverse("map_clone", kwargs={"map_id": anonymap.pk}) url = reverse("map_clone", kwargs={"map_id": anonymap.pk})
anonymap.edit_status = anonymap.ANONYMOUS anonymap.edit_status = anonymap.ANONYMOUS

View file

@ -6,16 +6,22 @@ pytestmark = pytest.mark.django_db
def test_tilelayer_json(): def test_tilelayer_json():
tilelayer = TileLayerFactory(attribution='Attribution', maxZoom=19, tilelayer = TileLayerFactory(
minZoom=0, name='Name', rank=1, tms=True, attribution="Attribution",
url_template='http://{s}.x.fr/{z}/{x}/{y}') maxZoom=19,
minZoom=0,
name="Name",
rank=1,
tms=True,
url_template="http://{s}.x.fr/{z}/{x}/{y}",
)
assert tilelayer.json == { assert tilelayer.json == {
'attribution': 'Attribution', "attribution": "Attribution",
'id': tilelayer.id, "id": tilelayer.id,
'maxZoom': 19, "maxZoom": 19,
'minZoom': 0, "minZoom": 0,
'name': 'Name', "name": "Name",
'rank': 1, "rank": 1,
'tms': True, "tms": True,
'url_template': 'http://{s}.x.fr/{z}/{x}/{y}' "url_template": "http://{s}.x.fr/{z}/{x}/{y}",
} }

View file

@ -1,5 +1,4 @@
from django.conf import settings from django.conf import settings
from django.urls import include, path, re_path
from django.conf.urls.i18n import i18n_patterns from django.conf.urls.i18n import i18n_patterns
from django.conf.urls.static import static from django.conf.urls.static import static
from django.contrib import admin from django.contrib import admin
@ -7,16 +6,17 @@ from django.contrib.auth import views as auth_views
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.staticfiles.storage import staticfiles_storage from django.contrib.staticfiles.storage import staticfiles_storage
from django.contrib.staticfiles.urls import staticfiles_urlpatterns from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.urls import include, path, re_path
from django.views.decorators.cache import cache_control, cache_page, never_cache from django.views.decorators.cache import cache_control, cache_page, never_cache
from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.generic.base import RedirectView from django.views.generic.base import RedirectView
from . import views from . import views
from .decorators import ( from .decorators import (
jsonize_view,
login_required_if_not_anonymous_allowed,
can_edit_map, can_edit_map,
can_view_map, can_view_map,
jsonize_view,
login_required_if_not_anonymous_allowed,
) )
from .utils import decorated_patterns from .utils import decorated_patterns

View file

@ -1,8 +1,7 @@
import gzip import gzip
import os import os
from django.urls import get_resolver from django.urls import URLPattern, URLResolver, get_resolver
from django.urls import URLPattern, URLResolver
def get_uri_template(urlname, args=None, prefix=""): def get_uri_template(urlname, args=None, prefix=""):

View file

@ -15,13 +15,13 @@ framework.
""" """
import os import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", os.environ.setdefault("DJANGO_SETTINGS_MODULE", "umap.settings")
"umap.settings")
# This application object is used by any WSGI server configured to use this # This application object is used by any WSGI server configured to use this
# file. This includes Django's development server, if the WSGI_APPLICATION # file. This includes Django's development server, if the WSGI_APPLICATION
# setting points here. # setting points here.
from django.core.wsgi import get_wsgi_application from django.core.wsgi import get_wsgi_application
application = get_wsgi_application() application = get_wsgi_application()
# Apply WSGI middleware here. # Apply WSGI middleware here.