Compare commits
12 commits
5ab11428a5
...
5ae83a571b
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5ae83a571b | ||
![]() |
be1fa55e9b | ||
![]() |
ac607370d0 | ||
![]() |
44aa914658 | ||
![]() |
c27e675152 | ||
![]() |
ee1a87cdeb | ||
![]() |
96895feea0 | ||
![]() |
359b0b41ca | ||
![]() |
3aa42d6f0f | ||
![]() |
fd8a1971f8 | ||
![]() |
a3baf82b7b | ||
![]() |
bf631f07de |
|
@ -28,6 +28,14 @@ Can be set through env var too: `ALLOWED_HOSTS=umap.mydomain.org,u.mydomain.org`
|
|||
|
||||
Set it to `True` for easier debugging in case of error.
|
||||
|
||||
#### DEPRECATED_AUTHENTICATION_PROVIDERS
|
||||
|
||||
List of auth providers to deprecate. Defining this will display a message to
|
||||
all users using this provider, to encourage them to configure another provider to
|
||||
their account.
|
||||
|
||||
DEPRECATED_AUTHENTICATION_PROVIDERS = ["social_core.backends.twitter_oauth2.TwitterOAuth2"]
|
||||
|
||||
#### EMAIL_BACKEND
|
||||
|
||||
Must be configured if you want uMap to send emails to anonymous users.
|
||||
|
@ -98,7 +106,12 @@ Eg.: `SHORT_SITE_URL=https://u.umap.org`
|
|||
|
||||
#### SITE_NAME
|
||||
|
||||
The name of the site, to be used in header and HTML title.
|
||||
The name of the site, to be used in header.
|
||||
|
||||
|
||||
#### SITE_DESCRIPTION
|
||||
|
||||
The description of the site, to be used in HTML title.
|
||||
|
||||
|
||||
#### SITE_URL
|
||||
|
|
|
@ -7,6 +7,7 @@ def settings(request):
|
|||
return {
|
||||
"UMAP_HELP_URL": djsettings.UMAP_HELP_URL,
|
||||
"SITE_NAME": djsettings.SITE_NAME,
|
||||
"SITE_DESCRIPTION": djsettings.SITE_DESCRIPTION,
|
||||
"SITE_URL": djsettings.SITE_URL,
|
||||
"ENABLE_ACCOUNT_LOGIN": djsettings.ENABLE_ACCOUNT_LOGIN,
|
||||
"UMAP_READONLY": djsettings.UMAP_READONLY,
|
||||
|
|
|
@ -2,7 +2,7 @@ from datetime import datetime, timedelta
|
|||
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from umap.models import Map
|
||||
from umap.models import DataLayer, Map
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
@ -33,3 +33,14 @@ class Command(BaseCommand):
|
|||
if not options["dry_run"]:
|
||||
map.delete()
|
||||
print(f"Deleted map {map_name} ({map_id}), trashed at {trashed_at}")
|
||||
print(f"Deleting layers in trash since {since}")
|
||||
layers = DataLayer.objects.filter(
|
||||
share_status=DataLayer.DELETED, modified_at__lt=since
|
||||
)
|
||||
for layer in layers:
|
||||
layer_id = layer.uuid
|
||||
layer_name = layer.name
|
||||
trashed_at = layer.modified_at.date()
|
||||
if not options["dry_run"]:
|
||||
layer.delete()
|
||||
print(f"Deleted layer {layer_name} ({layer_id}), trashed at {trashed_at}")
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# Generated by Django 5.1.4 on 2025-01-29 18:06
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("umap", "0025_alter_datalayer_geojson"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="datalayer",
|
||||
name="modified_at",
|
||||
field=models.DateTimeField(auto_now=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="datalayer",
|
||||
name="share_status",
|
||||
field=models.SmallIntegerField(
|
||||
choices=[(0, "Inherit"), (99, "Deleted")],
|
||||
default=0,
|
||||
verbose_name="share status",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -247,9 +247,13 @@ class Map(NamedModel):
|
|||
except KeyError:
|
||||
return ""
|
||||
|
||||
@property
|
||||
def datalayers(self):
|
||||
return self.datalayer_set.filter(share_status=DataLayer.INHERIT).all()
|
||||
|
||||
@property
|
||||
def preview_settings(self):
|
||||
layers = self.datalayer_set.all()
|
||||
layers = self.datalayers
|
||||
datalayer_data = [c.metadata() for c in layers]
|
||||
map_settings = self.settings
|
||||
if "properties" not in map_settings:
|
||||
|
@ -278,6 +282,7 @@ class Map(NamedModel):
|
|||
def delete(self, **kwargs):
|
||||
# Explicitely call datalayers.delete, so we can deal with removing files
|
||||
# (the cascade delete would not call the model delete method)
|
||||
# Use datalayer_set so to get also the deleted ones.
|
||||
for datalayer in self.datalayer_set.all():
|
||||
datalayer.delete()
|
||||
return super().delete(**kwargs)
|
||||
|
@ -287,7 +292,7 @@ class Map(NamedModel):
|
|||
umapjson["type"] = "umap"
|
||||
umapjson["uri"] = request.build_absolute_uri(self.get_absolute_url())
|
||||
datalayers = []
|
||||
for datalayer in self.datalayer_set.all():
|
||||
for datalayer in self.datalayers:
|
||||
with datalayer.geojson.open("rb") as f:
|
||||
layer = json.loads(f.read())
|
||||
if datalayer.settings:
|
||||
|
@ -406,7 +411,7 @@ class Map(NamedModel):
|
|||
new.save()
|
||||
for editor in self.editors.all():
|
||||
new.editors.add(editor)
|
||||
for datalayer in self.datalayer_set.all():
|
||||
for datalayer in self.datalayers:
|
||||
datalayer.clone(map_inst=new)
|
||||
return new
|
||||
|
||||
|
@ -458,6 +463,11 @@ class DataLayer(NamedModel):
|
|||
ANONYMOUS = 1
|
||||
COLLABORATORS = 2
|
||||
OWNER = 3
|
||||
DELETED = 99
|
||||
SHARE_STATUS = (
|
||||
(INHERIT, _("Inherit")),
|
||||
(DELETED, _("Deleted")),
|
||||
)
|
||||
EDIT_STATUS = (
|
||||
(INHERIT, _("Inherit")),
|
||||
(ANONYMOUS, _("Everyone")),
|
||||
|
@ -490,6 +500,12 @@ class DataLayer(NamedModel):
|
|||
default=INHERIT,
|
||||
verbose_name=_("edit status"),
|
||||
)
|
||||
share_status = models.SmallIntegerField(
|
||||
choices=SHARE_STATUS,
|
||||
default=INHERIT,
|
||||
verbose_name=_("share status"),
|
||||
)
|
||||
modified_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ("rank",)
|
||||
|
@ -568,6 +584,10 @@ class DataLayer(NamedModel):
|
|||
can = True
|
||||
return can
|
||||
|
||||
def move_to_trash(self):
|
||||
self.share_status = DataLayer.DELETED
|
||||
self.save()
|
||||
|
||||
|
||||
class Star(models.Model):
|
||||
at = models.DateTimeField(auto_now=True)
|
||||
|
|
|
@ -267,6 +267,7 @@ UMAP_KEEP_VERSIONS = env.int("UMAP_KEEP_VERSIONS", default=10)
|
|||
SITE_URL = env("SITE_URL", default="http://umap.org")
|
||||
SHORT_SITE_URL = env("SHORT_SITE_URL", default=None)
|
||||
SITE_NAME = "uMap"
|
||||
SITE_DESCRIPTION = "Online map creator"
|
||||
UMAP_DEMO_SITE = env("UMAP_DEMO_SITE", default=False)
|
||||
UMAP_EXCLUDE_DEFAULT_MAPS = False
|
||||
UMAP_MAPS_PER_PAGE = 5
|
||||
|
@ -305,6 +306,7 @@ LOGIN_URL = "login"
|
|||
SOCIAL_AUTH_LOGIN_REDIRECT_URL = "/login/popup/end/"
|
||||
|
||||
AUTHENTICATION_BACKENDS = ()
|
||||
DEPRECATED_AUTHENTICATION_BACKENDS = []
|
||||
|
||||
SOCIAL_AUTH_OPENSTREETMAP_OAUTH2_KEY = env(
|
||||
"SOCIAL_AUTH_OPENSTREETMAP_OAUTH2_KEY", default=""
|
||||
|
|
Before Width: | Height: | Size: 8.9 KiB |
|
@ -41,33 +41,14 @@ body.login header {
|
|||
display: inline-block;
|
||||
}
|
||||
|
||||
.login-grid span,
|
||||
.login-grid a {
|
||||
border: 1px solid #e5e5e5;
|
||||
padding: 5px;
|
||||
color: #000;
|
||||
background-position: center bottom;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 92px 92px;
|
||||
height: 92px;
|
||||
width: 92px;
|
||||
margin-inline-end: 10px;
|
||||
}
|
||||
.login-grid .login-github {
|
||||
background-image: url("./github.png");
|
||||
}
|
||||
.login-grid .login-bitbucket {
|
||||
background-image: url("./bitbucket.png");
|
||||
}
|
||||
.login-grid .login-twitter-oauth2 {
|
||||
background-image: url("./twitter.png");
|
||||
}
|
||||
.login-grid .login-openstreetmap,
|
||||
.login-grid .login-openstreetmap-oauth2 {
|
||||
background-image: url("./openstreetmap.png");
|
||||
}
|
||||
.login-grid .login-keycloak {
|
||||
background-image: url("./keycloak.png");
|
||||
}
|
||||
|
||||
/* **************************** */
|
||||
/* home */
|
||||
|
|
Before Width: | Height: | Size: 1.5 KiB |
BIN
umap/static/umap/img/providers/bitbucket.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
umap/static/umap/img/providers/github.png
Normal file
After Width: | Height: | Size: 608 B |
BIN
umap/static/umap/img/providers/keycloak.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
umap/static/umap/img/providers/openstreetmap-oauth2.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
umap/static/umap/img/providers/twitter-oauth2.png
Normal file
After Width: | Height: | Size: 545 B |
|
@ -1191,11 +1191,13 @@ Fields.TernaryChoices = class extends Fields.MultiChoice {
|
|||
|
||||
Fields.NullableChoices = class extends Fields.TernaryChoices {
|
||||
getChoices() {
|
||||
return [
|
||||
return (
|
||||
this.properties.choices || [
|
||||
[true, translate('always')],
|
||||
[false, translate('never')],
|
||||
['null', translate('hidden')],
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -447,6 +447,11 @@ export const SCHEMA = {
|
|||
label: translate('Display label'),
|
||||
inheritable: true,
|
||||
default: false,
|
||||
choices: [
|
||||
[true, translate('always')],
|
||||
[false, translate('never')],
|
||||
['null', translate('on hover')],
|
||||
],
|
||||
},
|
||||
slideshow: {
|
||||
type: Object,
|
||||
|
|
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 3.1 KiB |
|
@ -2,6 +2,10 @@
|
|||
|
||||
{% load i18n %}
|
||||
|
||||
{% block head_title %}
|
||||
{% blocktranslate %}{{ current_user }}’s maps{% endblocktranslate %} - {{ SITE_DESCRIPTION }}
|
||||
{% endblock head_title %}
|
||||
|
||||
{% block maincontent %}
|
||||
<div class="col wide">
|
||||
<h2 class="section">
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
{% extends "umap/content.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load i18n static %}
|
||||
|
||||
{% block head_title %}
|
||||
{% translate "My Profile" %} - {{ SITE_DESCRIPTION }}
|
||||
{% endblock head_title %}
|
||||
{% block maincontent %}
|
||||
{% include "umap/dashboard_menu.html" with selected="profile" %}
|
||||
<div class="wrapper">
|
||||
|
@ -28,8 +31,10 @@
|
|||
</h3>
|
||||
<ul>
|
||||
{% for name in providers %}
|
||||
<li>
|
||||
{{ name|title }}
|
||||
<li class="login-grid">
|
||||
{% with "umap/img/providers/"|add:name|add:".png" as path %}
|
||||
<img src="{% static path %}" width="92px" height="92px" alt="{{ name }}" />
|
||||
{% endwith %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
@ -46,9 +51,7 @@
|
|||
{% for name in backends.backends %}
|
||||
{% if name not in providers %}
|
||||
<li>
|
||||
<a href="{% url "social:begin" name %}"
|
||||
class="umap-login-popup login-{{ name }}"
|
||||
title="{{ name|title }}"></a>
|
||||
{% include "umap/components/provider.html" with name=name %}
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
{% load i18n %}
|
||||
|
||||
{% block head_title %}
|
||||
{% blocktranslate %}{{ current_user }}’s starred maps{% endblocktranslate %} - {{ SITE_DESCRIPTION }}
|
||||
{% endblock head_title %}
|
||||
|
||||
{% block maincontent %}
|
||||
<div class="col wide">
|
||||
<h2 class="section">
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<head>
|
||||
<title>
|
||||
{% block head_title %}
|
||||
{{ SITE_NAME }}
|
||||
{{ SITE_NAME }} - {{ SITE_DESCRIPTION }}
|
||||
{% endblock head_title %}
|
||||
</title>
|
||||
<meta charset="utf-8">
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
{% load i18n %}
|
||||
|
||||
{% block head_title %}
|
||||
{% trans "Login" %}
|
||||
{% trans "Login" %} - {{ SITE_DESCRIPTION }}
|
||||
{% endblock head_title %}
|
||||
{% load umap_tags i18n %}
|
||||
|
||||
|
@ -55,10 +55,7 @@
|
|||
<ul class="login-grid block-grid">
|
||||
{% for name in backends.backends %}
|
||||
<li>
|
||||
<a rel="nofollow"
|
||||
href="{% url "social:begin" name %}"
|
||||
class="umap-login-popup login-{{ name }}"
|
||||
title="{{ name|title }}"></a>
|
||||
{% include "umap/components/provider.html" with name=name %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
{% extends "umap/content.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block head_title %}
|
||||
{% translate "About" %} - {{ SITE_DESCRIPTION }}
|
||||
{% endblock head_title %}
|
||||
|
||||
{% block maincontent %}
|
||||
{% include "umap/about_summary.html" %}
|
||||
|
|
8
umap/templates/umap/components/provider.html
Normal file
|
@ -0,0 +1,8 @@
|
|||
{% load static %}
|
||||
<a href="{% url "social:begin" name %}"
|
||||
class="umap-login-popup"
|
||||
title="{{ name|title }}">
|
||||
{% with "umap/img/providers/"|add:name|add:".png" as path %}
|
||||
<img src="{% static path %}" width="92px" height="92px" alt="{{ name }}" />
|
||||
{% endwith %}
|
||||
</a>
|
|
@ -3,7 +3,7 @@
|
|||
{% load umap_tags i18n %}
|
||||
|
||||
{% block head_title %}
|
||||
{{ map.name }} - {{ SITE_NAME }}
|
||||
{{ map.name }} - {{ SITE_NAME }} - {{ SITE_DESCRIPTION }}
|
||||
{% endblock head_title %}
|
||||
{% block body_class %}
|
||||
map_detail
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
{% load i18n %}
|
||||
|
||||
{% block head_title %}
|
||||
{% translate "Password change" %} - {{ SITE_DESCRIPTION }}
|
||||
{% endblock head_title %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="section">
|
||||
{% trans "Password change" %}
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
{% load i18n %}
|
||||
|
||||
{% block head_title %}
|
||||
{% translate "Password change successful" %} - {{ SITE_DESCRIPTION }}
|
||||
{% endblock head_title %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="section">
|
||||
{% trans "Password change successful" %}
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
{% load i18n %}
|
||||
|
||||
{% block head_title %}
|
||||
{% translate "Explore maps" %} - {{ SITE_DESCRIPTION }}
|
||||
{% endblock head_title %}
|
||||
|
||||
{% block messages %}
|
||||
{# We don't want maps from the results list to display errors in the main page. #}
|
||||
{% endblock messages %}
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
{% load i18n %}
|
||||
|
||||
{% block head_title %}
|
||||
{% translate "Team deletion" %} - {{ SITE_DESCRIPTION }}
|
||||
{% endblock head_title %}
|
||||
|
||||
{% block maincontent %}
|
||||
{% include "umap/dashboard_menu.html" with selected="teams" %}
|
||||
<div class="wrapper">
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
{% load i18n %}
|
||||
|
||||
{% block head_title %}
|
||||
{% blocktranslate %}{{ current_team }}’s maps{% endblocktranslate %} - {{ SITE_DESCRIPTION }}
|
||||
{% endblock head_title %}
|
||||
|
||||
{% block maincontent %}
|
||||
<div class="wrapper">
|
||||
<div class="row">
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
{% load i18n %}
|
||||
|
||||
{% block head_title %}
|
||||
{% translate "Create or edit a team" %} - {{ SITE_DESCRIPTION }}
|
||||
{% endblock head_title %}
|
||||
|
||||
{% block maincontent %}
|
||||
{% include "umap/dashboard_menu.html" with selected="teams" %}
|
||||
<div class="wrapper">
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
{% load i18n static %}
|
||||
|
||||
{% block head_title %}
|
||||
{{ SITE_NAME }} - {% trans "My Dashboard" %}
|
||||
{% translate "My Dashboard" %} - {{ SITE_DESCRIPTION }}
|
||||
{% endblock head_title %}
|
||||
{% block maincontent %}
|
||||
{% trans "Search my maps" as placeholder %}
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
{% load i18n %}
|
||||
|
||||
{% block head_title %}
|
||||
{% translate "My Teams" %} - {{ SITE_DESCRIPTION }}
|
||||
{% endblock head_title %}
|
||||
|
||||
{% block maincontent %}
|
||||
{% include "umap/dashboard_menu.html" with selected="teams" %}
|
||||
<div class="wrapper">
|
||||
|
|
|
@ -8,7 +8,7 @@ from umap.models import Map
|
|||
|
||||
def test_page_title(page, live_server):
|
||||
page.goto(live_server.url)
|
||||
expect(page).to_have_title("uMap")
|
||||
expect(page).to_have_title("uMap - Online map creator")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -83,7 +83,7 @@ def test_login_from_map_page(live_server, page, tilelayer, settings, user, conte
|
|||
page.get_by_role("button", name="Save").click()
|
||||
assert Map.objects.count() == 0
|
||||
login_page = login_page_info.value
|
||||
expect(login_page).to_have_title("Login")
|
||||
expect(login_page).to_have_title("Login - Online map creator")
|
||||
login_page.get_by_placeholder("Username").fill(user.username)
|
||||
login_page.get_by_placeholder("Password").fill("123123")
|
||||
with page.expect_response(re.compile(r".*/map/create/")):
|
||||
|
|
|
@ -158,11 +158,14 @@ def test_should_not_be_possible_to_update_with_wrong_map_id_in_url(
|
|||
|
||||
|
||||
def test_delete(client, datalayer, map):
|
||||
assert map.datalayers.count() == 1
|
||||
url = reverse("datalayer_delete", args=(map.pk, datalayer.pk))
|
||||
client.login(username=map.owner.username, password="123123")
|
||||
response = client.post(url, {}, follow=True)
|
||||
assert response.status_code == 200
|
||||
assert not DataLayer.objects.filter(pk=datalayer.pk).count()
|
||||
assert DataLayer.objects.filter(pk=datalayer.pk).count()
|
||||
assert map.datalayers.count() == 0
|
||||
assert DataLayer.objects.get(pk=datalayer.pk).share_status == DataLayer.DELETED
|
||||
# Check that map has not been impacted
|
||||
assert Map.objects.filter(pk=map.pk).exists()
|
||||
# Test response is a json
|
||||
|
|
|
@ -4,15 +4,17 @@ from unittest import mock
|
|||
import pytest
|
||||
from django.core.management import call_command
|
||||
|
||||
from umap.models import Map
|
||||
from umap.models import DataLayer, Map
|
||||
|
||||
from .base import MapFactory
|
||||
from .base import DataLayerFactory, MapFactory
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
def test_empty_trash(user):
|
||||
recent = MapFactory(owner=user)
|
||||
recent_layer = DataLayerFactory(map=recent)
|
||||
deleted_layer = DataLayerFactory(map=recent)
|
||||
recent_deleted = MapFactory(owner=user)
|
||||
recent_deleted.move_to_trash()
|
||||
recent_deleted.save()
|
||||
|
@ -20,15 +22,20 @@ def test_empty_trash(user):
|
|||
mocked.return_value = datetime.utcnow() - timedelta(days=8)
|
||||
old_deleted = MapFactory(owner=user)
|
||||
old_deleted.move_to_trash()
|
||||
old_deleted.save()
|
||||
deleted_layer.move_to_trash()
|
||||
old = MapFactory(owner=user)
|
||||
assert Map.objects.count() == 4
|
||||
assert DataLayer.objects.count() == 2
|
||||
call_command("empty_trash", "--days=7", "--dry-run")
|
||||
assert Map.objects.count() == 4
|
||||
assert DataLayer.objects.count() == 2
|
||||
call_command("empty_trash", "--days=9")
|
||||
assert Map.objects.count() == 4
|
||||
assert DataLayer.objects.count() == 2
|
||||
call_command("empty_trash", "--days=7")
|
||||
assert not Map.objects.filter(pk=old_deleted.pk)
|
||||
assert Map.objects.filter(pk=old.pk)
|
||||
assert Map.objects.filter(pk=recent.pk)
|
||||
assert Map.objects.filter(pk=recent_deleted.pk)
|
||||
assert not DataLayer.objects.filter(pk=deleted_layer.pk)
|
||||
assert DataLayer.objects.filter(pk=recent_layer.pk)
|
||||
|
|
|
@ -810,6 +810,17 @@ def test_oembed_shared_status_map(client, map, datalayer, share_status):
|
|||
assert response.status_code == 403
|
||||
|
||||
|
||||
def test_download_does_not_include_delete_datalayers(client, map, datalayer):
|
||||
datalayer.share_status = DataLayer.DELETED
|
||||
datalayer.save()
|
||||
url = reverse("map_download", args=(map.pk,))
|
||||
response = client.get(url)
|
||||
assert response.status_code == 200
|
||||
# Test response is a json
|
||||
j = json.loads(response.content.decode())
|
||||
assert j["layers"] == []
|
||||
|
||||
|
||||
def test_oembed_no_url_map(client, map, datalayer):
|
||||
url = reverse("map_oembed")
|
||||
response = client.get(url)
|
||||
|
|
|
@ -15,7 +15,7 @@ from urllib.request import Request, build_opener
|
|||
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth import BACKEND_SESSION_KEY, get_user_model
|
||||
from django.contrib.auth import logout as do_logout
|
||||
from django.contrib.gis.measure import D
|
||||
from django.contrib.postgres.search import SearchQuery, SearchVector
|
||||
|
@ -742,14 +742,14 @@ class MapView(MapDetailMixin, PermissionsMixin, DetailView):
|
|||
def get_datalayers(self):
|
||||
# When initializing datalayers from map, we cannot get the reference version
|
||||
# the normal way, which is from the header X-Reference-Version
|
||||
return [dl.metadata(self.request) for dl in self.object.datalayer_set.all()]
|
||||
return [dl.metadata(self.request) for dl in self.object.datalayers]
|
||||
|
||||
@property
|
||||
def edit_mode(self):
|
||||
edit_mode = "disabled"
|
||||
if self.object.can_edit(self.request):
|
||||
edit_mode = "advanced"
|
||||
elif any(d.can_edit(self.request) for d in self.object.datalayer_set.all()):
|
||||
elif any(d.can_edit(self.request) for d in self.object.datalayers):
|
||||
edit_mode = "simple"
|
||||
return edit_mode
|
||||
|
||||
|
@ -1325,7 +1325,7 @@ class DataLayerDelete(DeleteView):
|
|||
self.object = self.get_object()
|
||||
if self.object.map != self.kwargs["map_inst"]:
|
||||
return HttpResponseForbidden()
|
||||
self.object.delete()
|
||||
self.object.move_to_trash()
|
||||
return simple_json_response(info=_("Layer successfully deleted."))
|
||||
|
||||
|
||||
|
@ -1419,3 +1419,18 @@ class LoginPopupEnd(TemplateView):
|
|||
"""
|
||||
|
||||
template_name = "umap/login_popup_end.html"
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
backend = self.request.session[BACKEND_SESSION_KEY]
|
||||
if backend in settings.DEPRECATED_AUTHENTICATION_BACKENDS:
|
||||
name = backend.split(".")[-1]
|
||||
messages.error(
|
||||
self.request,
|
||||
_(
|
||||
"Using “%(name)s” to authenticate is deprecated. "
|
||||
"Please configure another provider in your profile page."
|
||||
)
|
||||
% {"name": name},
|
||||
)
|
||||
return HttpResponseRedirect(reverse("user_profile"))
|
||||
return super().get(*args, **kwargs)
|
||||
|
|