From 6e9e46dbbddd119d5aee37b87bc34a21cad3d45d Mon Sep 17 00:00:00 2001 From: David Larlet Date: Mon, 25 Sep 2023 17:48:57 -0400 Subject: [PATCH] Create an API for uMap with DRF Refs #1333 --- pyproject.toml | 1 + umap/api_views.py | 59 ++++++++++++++++++++++++++++++ umap/decorators.py | 4 +- umap/forms.py | 29 --------------- umap/serializers.py | 32 ++++++++++++++++ umap/settings/base.py | 6 +++ umap/static/umap/js/umap.js | 15 ++++++-- umap/static/umap/js/umap.xhr.js | 8 +++- umap/static/umap/test/DataLayer.js | 52 +++++++++----------------- umap/static/umap/test/_pre.js | 4 +- umap/tests/test_map.py | 11 +++--- umap/tests/test_map_views.py | 51 +++++++++++++------------- umap/urls.py | 9 +++-- umap/views.py | 47 +----------------------- 14 files changed, 174 insertions(+), 154 deletions(-) create mode 100644 umap/api_views.py create mode 100644 umap/serializers.py diff --git a/pyproject.toml b/pyproject.toml index 7831d31a..50262351 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,6 +33,7 @@ classifiers = [ ] dependencies = [ "Django>=4.1", + "djangorestframework==3.14.0", "django-agnocomplete==2.2.0", "django-compressor==4.3.1", "django-environ==0.10.0", diff --git a/umap/api_views.py b/umap/api_views.py new file mode 100644 index 00000000..01c00dab --- /dev/null +++ b/umap/api_views.py @@ -0,0 +1,59 @@ +from rest_framework import generics, status +from rest_framework.response import Response + +from .models import Map +from .serializers import MapSerializer +from .views import ANONYMOUS_COOKIE_MAX_AGE + + +class MapList(generics.ListCreateAPIView): + queryset = Map.public.all().order_by("-modified_at") + serializer_class = MapSerializer + + def perform_create(self, serializer): + if self.request.user.is_authenticated: + serializer.save(owner=self.request.user) + else: + serializer.save() + + def get_map_permissions(self, map_): + permissions = {} + permissions["edit_status"] = map_.edit_status + permissions["share_status"] = map_.share_status + if map_.owner: + permissions["owner"] = { + "id": map_.owner.pk, + "name": str(map_.owner), + "url": map_.owner.get_url(), + } + permissions["editors"] = [ + {"id": editor.pk, "name": str(editor)} for editor in map_.editors.all() + ] + if not map_.owner and map_.is_anonymous_owner(self.request): + permissions["anonymous_edit_url"] = map_.get_anonymous_edit_url() + return permissions + + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + map_ = serializer.instance + headers = self.get_success_headers(serializer.data) + data = serializer.data + permissions = self.get_map_permissions(map_) + if not map_.owner: + anonymous_url = map_.get_anonymous_edit_url() + permissions["anonymous_edit_url"] = anonymous_url + data["permissions"] = permissions + response = Response(data, status=status.HTTP_201_CREATED, headers=headers) + if not self.request.user.is_authenticated: + key, value = map_.signed_cookie_elements + response.set_signed_cookie( + key=key, value=value, max_age=ANONYMOUS_COOKIE_MAX_AGE + ) + return response + + +class MapDetail(generics.RetrieveUpdateDestroyAPIView): + queryset = Map.public.all().order_by("-modified_at") + serializer_class = MapSerializer diff --git a/umap/decorators.py b/umap/decorators.py index b9b5232a..2c36ebf6 100644 --- a/umap/decorators.py +++ b/umap/decorators.py @@ -33,7 +33,7 @@ def can_edit_map(view_func): @wraps(view_func) def wrapper(request, *args, **kwargs): - map_inst = get_object_or_404(Map, pk=kwargs["map_id"]) + map_inst = get_object_or_404(Map, pk=kwargs.get("map_id", kwargs.get("pk"))) user = request.user kwargs["map_inst"] = map_inst # Avoid rerequesting the map in the view if map_inst.edit_status >= map_inst.EDITORS: @@ -54,7 +54,7 @@ def can_view_map(view_func): @wraps(view_func) def wrapper(request, *args, **kwargs): - map_inst = get_object_or_404(Map, pk=kwargs["map_id"]) + map_inst = get_object_or_404(Map, pk=kwargs.get("map_id", kwargs.get("pk"))) kwargs["map_inst"] = map_inst # Avoid rerequesting the map in the view if not map_inst.can_view(request): return HttpResponseForbidden() diff --git a/umap/forms.py b/umap/forms.py index ec94e7a8..b769f40e 100644 --- a/umap/forms.py +++ b/umap/forms.py @@ -2,7 +2,6 @@ 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.forms.utils import ErrorList @@ -78,34 +77,6 @@ class AnonymousDataLayerPermissionsForm(forms.ModelForm): fields = ("edit_status",) -class MapSettingsForm(forms.ModelForm): - def __init__(self, *args, **kwargs): - super(MapSettingsForm, self).__init__(*args, **kwargs) - self.fields["slug"].required = False - self.fields["center"].widget.map_srid = 4326 - - def clean_slug(self): - slug = self.cleaned_data.get("slug", None) - name = self.cleaned_data.get("name", None) - if not slug and name: - # If name is empty, don't do nothing, validation will raise - # later on the process because name is required - self.cleaned_data["slug"] = slugify(name) or "map" - return self.cleaned_data["slug"][:50] - else: - return "" - - def clean_center(self): - if not self.cleaned_data["center"]: - point = DEFAULT_CENTER - self.cleaned_data["center"] = point - return self.cleaned_data["center"] - - class Meta: - fields = ("settings", "name", "center", "slug") - model = Map - - class UserProfileForm(forms.ModelForm): class Meta: model = User diff --git a/umap/serializers.py b/umap/serializers.py new file mode 100644 index 00000000..946923e7 --- /dev/null +++ b/umap/serializers.py @@ -0,0 +1,32 @@ +from django.contrib.gis.geos import Point +from django.template.defaultfilters import slugify +from django.conf import settings +from rest_framework import serializers + +from .models import Map + +DEFAULT_LATITUDE = ( + settings.LEAFLET_LATITUDE if hasattr(settings, "LEAFLET_LATITUDE") else 51 +) +DEFAULT_LONGITUDE = ( + settings.LEAFLET_LONGITUDE if hasattr(settings, "LEAFLET_LONGITUDE") else 2 +) +DEFAULT_CENTER = Point(DEFAULT_LONGITUDE, DEFAULT_LATITUDE) + + +class MapSerializer(serializers.HyperlinkedModelSerializer): + slug = serializers.CharField(required=False) + + class Meta: + model = Map + fields = ["id", "name", "slug", "center", "settings"] + + def validate(self, data): + slug = data.get("slug") + name = data.get("name") + if not slug and name: + data["slug"] = slugify(name)[:50] or "map" + return data + + def validate_center(self, value): + return value or DEFAULT_CENTER diff --git a/umap/settings/base.py b/umap/settings/base.py index 33451aaa..a38522ad 100644 --- a/umap/settings/base.py +++ b/umap/settings/base.py @@ -122,6 +122,7 @@ INSTALLED_APPS = ( "umap", "compressor", "social_django", + "rest_framework", # See https://github.com/peopledoc/django-agnocomplete/commit/26eda2dfa4a2f8a805ca2ea19a0c504b9d773a1c # Django does not find the app config in the default place, so the app is not loaded # so the "autodiscover" is not run. @@ -281,6 +282,11 @@ if SOCIAL_AUTH_OPENSTREETMAP_KEY and SOCIAL_AUTH_OPENSTREETMAP_SECRET: ) AUTHENTICATION_BACKENDS += ("django.contrib.auth.backends.ModelBackend",) +REST_FRAMEWORK = { + # Use Django's standard `django.contrib.auth` permissions, + # or allow read-only access for unauthenticated users. + "DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.AllowAny"] +} LOGGING = { "version": 1, diff --git a/umap/static/umap/js/umap.js b/umap/static/umap/js/umap.js index 3e1a9fe3..af780edf 100644 --- a/umap/static/umap/js/umap.js +++ b/umap/static/umap/js/umap.js @@ -1102,7 +1102,8 @@ L.U.Map.include({ formData.append('name', this.options.name) formData.append('center', JSON.stringify(this.geometry())) formData.append('settings', JSON.stringify(geojson)) - this.post(this.getSaveUrl(), { + const method = this.options.umap_id ? this.put.bind(this) : this.post.bind(this) + method(this.getSaveUrl(), { data: formData, context: this, callback: function (data) { @@ -1192,13 +1193,13 @@ L.U.Map.include({ }, getEditUrl: function () { - return L.Util.template(this.options.urls.map_update, { - map_id: this.options.umap_id, + return L.Util.template(this.options.urls.map_detail, { + pk: this.options.umap_id, }) }, getCreateUrl: function () { - return L.Util.template(this.options.urls.map_create) + return L.Util.template(this.options.urls.map_list) }, getSaveUrl: function () { @@ -1855,6 +1856,12 @@ L.U.Map.include({ this.xhr.post(url, options) }, + put: function (url, options) { + options = options || {} + options.listener = this + this.xhr.put(url, options) + }, + get: function (url, options) { options = options || {} options.listener = this diff --git a/umap/static/umap/js/umap.xhr.js b/umap/static/umap/js/umap.xhr.js index 453579bb..fb7a87e8 100644 --- a/umap/static/umap/js/umap.xhr.js +++ b/umap/static/umap/js/umap.xhr.js @@ -60,7 +60,7 @@ L.U.Xhr = L.Evented.extend({ xhr.onreadystatechange = () => { if (xhr.readyState === 4) { - if (xhr.status == 200) { + if (xhr.status == 200 || xhr.status == 201) { settings.callback.call(settings.context || xhr, xhr.responseText, xhr) } else if (xhr.status === 403) { self.ui.alert({ @@ -130,7 +130,7 @@ L.U.Xhr = L.Evented.extend({ } const settings = L.Util.extend({}, default_options, options) - if (verb === 'POST') { + if (verb === 'POST' || verb === 'PUT') { // find a way not to make this django specific const token = document.cookie.replace( /(?:(?:^|.*;\s*)csrftoken\s*\=\s*([^;]*).*$)|^.*$/, @@ -186,6 +186,10 @@ L.U.Xhr = L.Evented.extend({ this._json('POST', uri, options) }, + put: function (uri, options) { + this._json('PUT', uri, options) + }, + submit_form: function (form_id, options) { if (typeof options === 'undefined') options = {} const form = L.DomUtil.get(form_id) diff --git a/umap/static/umap/test/DataLayer.js b/umap/static/umap/test/DataLayer.js index 3c545ff8..5a9ac0c1 100644 --- a/umap/static/umap/test/DataLayer.js +++ b/umap/static/umap/test/DataLayer.js @@ -76,11 +76,7 @@ describe('L.U.DataLayer', function () { it('should call datalayer.save on save button click', function (done) { sinon.spy(this.datalayer, 'save') this.server.flush() - this.server.respondWith( - 'POST', - '/map/99/update/settings/', - JSON.stringify({ id: 99 }) - ) + this.server.respondWith('PUT', '/map/99/', JSON.stringify({ id: 99 })) this.server.respondWith( 'POST', '/map/99/datalayer/update/62/', @@ -97,11 +93,7 @@ describe('L.U.DataLayer', function () { it('should show alert if server respond 412', function () { cleanAlert() this.server.flush() - this.server.respondWith( - 'POST', - '/map/99/update/settings/', - JSON.stringify({ id: 99 }) - ) + this.server.respondWith('PUT', '/map/99/', JSON.stringify({ id: 99 })) this.server.respondWith('POST', '/map/99/datalayer/update/62/', [412, {}, '']) happen.click(editButton) input = qs('form.umap-form input[name="name"]') @@ -178,11 +170,7 @@ describe('L.U.DataLayer', function () { it('should set umap_id on save callback', function () { assert.notOk(newDatalayer.umap_id) this.server.flush() - this.server.respondWith( - 'POST', - '/map/99/update/settings/', - JSON.stringify({ id: 99 }) - ) + this.server.respondWith('PUT', '/map/99/', JSON.stringify({ id: 99 })) this.server.respondWith( 'POST', '/map/99/datalayer/create/', @@ -219,11 +207,7 @@ describe('L.U.DataLayer', function () { } var spy = sinon.spy(response) this.server.flush() - this.server.respondWith( - 'POST', - '/map/99/update/settings/', - JSON.stringify({ id: 99 }) - ) + this.server.respondWith('PUT', '/map/99/', JSON.stringify({ id: 99 })) this.server.respondWith('POST', '/map/99/datalayer/update/63/', spy) clickSave() this.server.respond() @@ -404,8 +388,7 @@ describe('L.U.DataLayer', function () { }) }) - describe("#displayOnLoad", function () { - + describe('#displayOnLoad', function () { beforeEach(function () { this.server.respondWith( /\/datalayer\/64\/\?.*/, @@ -415,27 +398,26 @@ describe('L.U.DataLayer', function () { // Force fetching the data, so to deal here with fake server this.datalayer.fetchData() this.server.respond() - this.map.setZoom(10, {animate: false}) - }); + this.map.setZoom(10, { animate: false }) + }) afterEach(function () { this.datalayer._delete() }) - it("should not display layer at load", function () { + it('should not display layer at load', function () { assert.notOk(qs('path[fill="AliceBlue"]')) }) - it("should display on click", function () { + it('should display on click', function () { happen.click(qs(`[data-id='${L.stamp(this.datalayer)}'] .layer-toggle`)) assert.ok(qs('path[fill="AliceBlue"]')) }) - it("should not display on zoom", function () { - this.map.setZoom(9, {animate: false}) + it('should not display on zoom', function () { + this.map.setZoom(9, { animate: false }) assert.notOk(qs('path[fill="AliceBlue"]')) }) - }) describe('#facet-search()', function () { @@ -474,22 +456,22 @@ describe('L.U.DataLayer', function () { }) describe('#zoomEnd', function () { it('should honour the fromZoom option', function () { - this.map.setZoom(6, {animate: false}) + this.map.setZoom(6, { animate: false }) assert.ok(qs('path[fill="none"]')) this.datalayer.options.fromZoom = 6 - this.map.setZoom(5, {animate: false}) + this.map.setZoom(5, { animate: false }) assert.notOk(qs('path[fill="none"]')) - this.map.setZoom(6, {animate: false}) + this.map.setZoom(6, { animate: false }) assert.ok(qs('path[fill="none"]')) }) it('should honour the toZoom option', function () { - this.map.setZoom(6, {animate: false}) + this.map.setZoom(6, { animate: false }) assert.ok(qs('path[fill="none"]')) this.datalayer.options.toZoom = 6 - this.map.setZoom(7, {animate: false}) + this.map.setZoom(7, { animate: false }) assert.notOk(qs('path[fill="none"]')) - this.map.setZoom(6, {animate: false}) + this.map.setZoom(6, { animate: false }) assert.ok(qs('path[fill="none"]')) }) }) diff --git a/umap/static/umap/test/_pre.js b/umap/static/umap/test/_pre.js index 5df2e152..a74f2420 100644 --- a/umap/static/umap/test/_pre.js +++ b/umap/static/umap/test/_pre.js @@ -114,7 +114,8 @@ function initMap(options) { urls: { map: '/map/{slug}_{pk}', datalayer_view: '/datalayer/{pk}/', - map_update: '/map/{map_id}/update/settings/', + map_list: '/api/maps/', + map_detail: '/api/maps/{map_id}/', map_old_url: '/map/{username}/{slug}/', map_clone: '/map/{map_id}/update/clone/', map_short_url: '/m/{pk}/', @@ -122,7 +123,6 @@ function initMap(options) { map_new: '/map/new/', datalayer_update: '/map/{map_id}/datalayer/update/{pk}/', map_delete: '/map/{map_id}/update/delete/', - map_create: '/map/create/', logout: '/logout/', datalayer_create: '/map/{map_id}/datalayer/create/', login_popup_end: '/login/popupd/', diff --git a/umap/tests/test_map.py b/umap/tests/test_map.py index d0bb52e7..ced02a78 100644 --- a/umap/tests/test_map.py +++ b/umap/tests/test_map.py @@ -50,11 +50,13 @@ def test_editors_can_edit_if_status_editors(map, 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.edit_status = map.ANONYMOUS map.save() - url = reverse('map_update', kwargs={'map_id': map.pk}) + url = reverse("map_detail", kwargs={"pk": map.pk}) request = rf.get(url) request.user = user 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): clone = map.clone() 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.center == clone.center 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): map.share_status = map.PUBLIC open_map = MapFactory(owner=user, licence=licence, share_status=Map.OPEN) - private_map = MapFactory(owner=user, licence=licence, - share_status=Map.PRIVATE) + private_map = MapFactory(owner=user, licence=licence, share_status=Map.PRIVATE) assert map in Map.public.all() assert open_map not in Map.public.all() assert private_map not in Map.public.all() diff --git a/umap/tests/test_map_views.py b/umap/tests/test_map_views.py index 01e78c59..fe984b0b 100644 --- a/umap/tests/test_map_views.py +++ b/umap/tests/test_map_views.py @@ -24,13 +24,13 @@ def post_data(): def test_create(client, user, post_data): - url = reverse("map_create") - # POST only mendatory fields + url = reverse("map_list") + # POST only mandatory fields name = "test-map-with-new-name" post_data["name"] = name client.login(username=user.username, password="123123") response = client.post(url, post_data) - assert response.status_code == 200 + assert response.status_code == 201 j = json.loads(response.content.decode()) created_map = Map.objects.latest("pk") assert j["id"] == created_map.pk @@ -45,21 +45,22 @@ def test_create(client, user, post_data): } -def test_map_create_permissions(client, settings): +def test_map_list_permissions(client, settings): settings.UMAP_ALLOW_ANONYMOUS = False - url = reverse("map_create") + url = reverse("map_list") # POST anonymous response = client.post(url, {}) + assert response.status_code == 200 assert login_required(response) def test_map_update_access(client, map, user): - url = reverse("map_update", kwargs={"map_id": map.pk}) + url = reverse("map_detail", kwargs={"pk": map.pk}) # GET anonymous response = client.get(url) assert login_required(response) # POST anonymous - response = client.post(url, {}) + response = client.put(url, {}, content_type="application/json") assert login_required(response) # GET with wrong permissions client.login(username=user.username, password="123123") @@ -67,7 +68,7 @@ def test_map_update_access(client, map, user): assert response.status_code == 403 # POST with wrong permissions client.login(username=user.username, password="123123") - response = client.post(url, {}) + response = client.put(url, {}, content_type="application/json") assert response.status_code == 403 @@ -90,12 +91,12 @@ def test_map_update_permissions_access(client, map, user): def test_update(client, map, post_data): - url = reverse("map_update", kwargs={"map_id": map.pk}) - # POST only mendatory fields + url = reverse("map_detail", kwargs={"pk": map.pk}) + # PUT only mandatory fields name = "new map name" post_data["name"] = name client.login(username=map.owner.username, password="123123") - response = client.post(url, post_data) + response = client.put(url, post_data, content_type="application/json") assert response.status_code == 200 j = json.loads(response.content.decode()) assert "html" not in j @@ -198,13 +199,13 @@ def test_clone_should_set_cloner_as_owner(client, map, user): def test_map_creation_should_allow_unicode_names(client, map, post_data): - url = reverse("map_create") - # POST only mendatory fields + url = reverse("map_list") + # POST only mandatory fields name = "Академический" post_data["name"] = name client.login(username=map.owner.username, password="123123") response = client.post(url, post_data) - assert response.status_code == 200 + assert response.status_code == 201 j = json.loads(response.content.decode()) created_map = Map.objects.latest("pk") assert j["id"] == created_map.pk @@ -317,25 +318,25 @@ def test_logged_in_user_can_edit_map_editable_by_anonymous(client, map, user): map.edit_status = map.ANONYMOUS map.save() client.login(username=user.username, password="123123") - url = reverse("map_update", kwargs={"map_id": map.pk}) + url = reverse("map_detail", kwargs={"pk": map.pk}) new_name = "this is my new name" data = { "center": '{"type":"Point","coordinates":[13.447265624999998,48.94415123418794]}', # noqa "name": new_name, } - response = client.post(url, data) + response = client.put(url, data, content_type="application/json") assert response.status_code == 200 assert Map.objects.get(pk=map.pk).name == new_name @pytest.mark.usefixtures("allow_anonymous") def test_anonymous_create(cookieclient, post_data): - url = reverse("map_create") - # POST only mendatory fields + url = reverse("map_list") + # POST only mandatory fields name = "test-map-with-new-name" post_data["name"] = name response = cookieclient.post(url, post_data) - assert response.status_code == 200 + assert response.status_code == 201 j = json.loads(response.content.decode()) created_map = Map.objects.latest("pk") assert j["id"] == created_map.pk @@ -349,8 +350,8 @@ def test_anonymous_create(cookieclient, post_data): @pytest.mark.usefixtures("allow_anonymous") def test_anonymous_update_without_cookie_fails(client, anonymap, post_data): # noqa - url = reverse("map_update", kwargs={"map_id": anonymap.pk}) - response = client.post(url, post_data) + url = reverse("map_detail", kwargs={"pk": anonymap.pk}) + response = client.put(url, post_data, content_type="application/json") assert response.status_code == 403 @@ -358,11 +359,11 @@ def test_anonymous_update_without_cookie_fails(client, anonymap, post_data): # def test_anonymous_update_with_cookie_should_work( cookieclient, anonymap, post_data ): # noqa - url = reverse("map_update", kwargs={"map_id": anonymap.pk}) - # POST only mendatory fields + url = reverse("map_detail", kwargs={"pk": anonymap.pk}) + # POST only mandatory fields name = "new map name" post_data["name"] = name - response = cookieclient.post(url, post_data) + response = cookieclient.put(url, post_data, content_type="application/json") assert response.status_code == 200 j = json.loads(response.content.decode()) updated_map = Map.objects.get(pk=anonymap.pk) @@ -522,7 +523,7 @@ def test_map_attach_owner_anonymous_not_allowed(cookieclient, anonymap, user): def test_create_readonly(client, user, post_data, settings): settings.UMAP_READONLY = True - url = reverse("map_create") + url = reverse("map_list") client.login(username=user.username, password="123123") response = client.post(url, post_data) assert response.status_code == 403 diff --git a/umap/urls.py b/umap/urls.py index 630ea45a..638fe4f3 100644 --- a/umap/urls.py +++ b/umap/urls.py @@ -9,6 +9,7 @@ from django.contrib.staticfiles.urls import staticfiles_urlpatterns from django.views.decorators.cache import cache_control, cache_page, never_cache from django.views.decorators.csrf import ensure_csrf_cookie +from . import api_views from . import views from .decorators import ( jsonize_view, @@ -93,7 +94,7 @@ i18n_urls += decorated_patterns( ) i18n_urls += decorated_patterns( [login_required_if_not_anonymous_allowed, never_cache], - re_path(r"^map/create/$", views.MapCreate.as_view(), name="map_create"), + path("api/maps/", api_views.MapList.as_view(), name="map_list"), ) i18n_urls += decorated_patterns( [login_required], @@ -115,9 +116,9 @@ i18n_urls += decorated_patterns( ) map_urls = [ re_path( - r"^map/(?P[\d]+)/update/settings/$", - views.MapUpdate.as_view(), - name="map_update", + r"^api/map/(?P[\d]+)/$", + api_views.MapDetail.as_view(), + name="map_detail", ), re_path( r"^map/(?P[\d]+)/update/permissions/$", diff --git a/umap/views.py b/umap/views.py index 0d341585..a07c7edd 100644 --- a/umap/views.py +++ b/umap/views.py @@ -50,7 +50,6 @@ from .forms import ( AnonymousDataLayerPermissionsForm, AnonymousMapPermissionsForm, FlatErrorList, - MapSettingsForm, SendLinkForm, UpdateMapPermissionsForm, UserProfileForm, @@ -469,9 +468,7 @@ class MapDetailMixin: else: map_statuses = AnonymousMapPermissionsForm.STATUS datalayer_statuses = AnonymousDataLayerPermissionsForm.STATUS - properties["edit_statuses"] = [ - (i, str(label)) for i, label in map_statuses - ] + properties["edit_statuses"] = [(i, str(label)) for i, label in map_statuses] properties["datalayer_edit_statuses"] = [ (i, str(label)) for i, label in datalayer_statuses ] @@ -618,48 +615,6 @@ class MapNew(MapDetailMixin, TemplateView): template_name = "umap/map_detail.html" -class MapCreate(FormLessEditMixin, PermissionsMixin, CreateView): - model = Map - form_class = MapSettingsForm - - def form_valid(self, form): - if self.request.user.is_authenticated: - form.instance.owner = self.request.user - self.object = form.save() - permissions = self.get_permissions() - # User does not have the cookie yet. - if not self.object.owner: - anonymous_url = self.object.get_anonymous_edit_url() - permissions["anonymous_edit_url"] = anonymous_url - response = simple_json_response( - id=self.object.pk, - url=self.object.get_absolute_url(), - permissions=permissions, - ) - if not self.request.user.is_authenticated: - key, value = self.object.signed_cookie_elements - response.set_signed_cookie( - key=key, value=value, max_age=ANONYMOUS_COOKIE_MAX_AGE - ) - return response - - -class MapUpdate(FormLessEditMixin, PermissionsMixin, UpdateView): - model = Map - form_class = MapSettingsForm - pk_url_kwarg = "map_id" - - def form_valid(self, form): - self.object.settings = form.cleaned_data["settings"] - self.object.save() - return simple_json_response( - id=self.object.pk, - url=self.object.get_absolute_url(), - permissions=self.get_permissions(), - info=_("Map has been updated!"), - ) - - class UpdateMapPermissions(FormLessEditMixin, UpdateView): model = Map pk_url_kwarg = "map_id"