diff --git a/umap/models.py b/umap/models.py index 8f12ade7..8c3f4e6a 100644 --- a/umap/models.py +++ b/umap/models.py @@ -444,7 +444,7 @@ class DataLayer(NamedModel): (OWNER, _("Owner only")), ) uuid = models.UUIDField( - unique=True, primary_key=True, default=uuid.uuid4, editable=False + unique=True, primary_key=True, default=uuid.uuid4, editable=True ) old_id = models.IntegerField(null=True, blank=True) map = models.ForeignKey(Map, on_delete=models.CASCADE) diff --git a/umap/static/umap/js/modules/data/features.js b/umap/static/umap/js/modules/data/features.js index 260ed28f..3b39bbe8 100644 --- a/umap/static/umap/js/modules/data/features.js +++ b/umap/static/umap/js/modules/data/features.js @@ -139,7 +139,7 @@ class Feature { subject: 'feature', metadata: { id: this.id, - layerId: this.datalayer?.umap_id || null, + layerId: this.datalayer.umap_id, featureType: this.getClassName(), }, } diff --git a/umap/static/umap/js/modules/data/layer.js b/umap/static/umap/js/modules/data/layer.js index 795a1f7d..3dc07ad6 100644 --- a/umap/static/umap/js/modules/data/layer.js +++ b/umap/static/umap/js/modules/data/layer.js @@ -36,7 +36,7 @@ const LAYER_MAP = LAYER_TYPES.reduce((acc, klass) => { }, {}) export class DataLayer { - constructor(map, data) { + constructor(map, data, sync) { this.map = map this.sync = map.sync_engine.proxy(this) this._index = Array() @@ -78,7 +78,9 @@ export class DataLayer { this.backupOptions() this.connectToMap() this.permissions = new DataLayerPermissions(this) - if (!this.umap_id) { + + if (!this.createdOnServer) { + // When importing data, show the layer immediately if applicable if (this.showAtLoad()) this.show() this.isDirty = true } @@ -89,6 +91,11 @@ export class DataLayer { if (this.isVisible()) this.propagateShow() } + get createdOnServer(){ + console.log("reference version", this._reference_version) + return this._reference_version !== undefined + } + set isDirty(status) { this._isDirty = status if (status) { @@ -119,7 +126,7 @@ export class DataLayer { return { subject: 'datalayer', metadata: { - id: this.umap_id || null, + id: this.umap_id, }, } } @@ -212,7 +219,7 @@ export class DataLayer { } async fetchData() { - if (!this.umap_id) return + if (!this.createdOnServer) return if (this._loading) return this._loading = true const [geojson, response, error] = await this.map.server.get(this._dataUrl()) @@ -304,7 +311,7 @@ export class DataLayer { } isLoaded() { - return !this.umap_id || this._loaded + return !this.createdOnServer || this._loaded } hasDataLoaded() { @@ -312,8 +319,13 @@ export class DataLayer { } setUmapId(id) { - // Datalayer is null when listening creation form + // Datalayer ID is null when listening creation form if (!this.umap_id && id) this.umap_id = id + else { + // Generate a random uuid if none is provided + this.umap_id = crypto.randomUUID() + console.log('Generating random UUID for datalayer', this.umap_id) + } } backupOptions() { @@ -571,7 +583,7 @@ export class DataLayer { } reset() { - if (!this.umap_id) this.erase() + if (!this.createdOnServer) this.erase() this.resetOptions() this.parentPane.appendChild(this.pane) @@ -1040,14 +1052,16 @@ export class DataLayer { // Filename support is shaky, don't do it for now. const blob = new Blob([JSON.stringify(geojson)], { type: 'application/json' }) formData.append('geojson', blob) - const saveUrl = this.map.urls.get('datalayer_save', { + const saveURL = this.map.urls.get('datalayer_save', { map_id: this.map.options.umap_id, pk: this.umap_id, + created: this.createdOnServer, }) + console.log("saveUrl", saveURL) const headers = this._reference_version ? { 'X-Datalayer-Reference': this._reference_version } : {} - await this._trySave(saveUrl, headers, formData) + await this._trySave(saveURL, headers, formData) this._geojson = geojson } @@ -1076,7 +1090,7 @@ export class DataLayer { this._reference_version = response.headers.get('X-Datalayer-Version') this.sync.update('_reference_version', this._reference_version) - this.setUmapId(data.id) + // this.setUmapId(data.id) this.updateOptions(data) this.backupOptions() this.connectToMap() diff --git a/umap/static/umap/js/modules/urls.js b/umap/static/umap/js/modules/urls.js index c3cb8a2a..1fcb1542 100644 --- a/umap/static/umap/js/modules/urls.js +++ b/umap/static/umap/js/modules/urls.js @@ -25,8 +25,8 @@ export default class URLs { } // Update the layer if pk is passed, create otherwise. - datalayer_save({ map_id, pk }, ...options) { - if (pk) return this.get('datalayer_update', { map_id, pk }, ...options) + datalayer_save({ map_id, pk, created}, ...options) { + if (created) return this.get('datalayer_update', { map_id, pk }, ...options) return this.get('datalayer_create', { map_id, pk }, ...options) } } diff --git a/umap/urls.py b/umap/urls.py index aaab2beb..b3afb557 100644 --- a/umap/urls.py +++ b/umap/urls.py @@ -155,8 +155,8 @@ map_urls = [ views.MapClone.as_view(), name="map_clone", ), - re_path( - r"^map/(?P[\d]+)/datalayer/create/$", + path( + "map//datalayer/create//", views.DataLayerCreate.as_view(), name="datalayer_create", ), diff --git a/umap/views.py b/umap/views.py index 5726a838..2aa418fb 100644 --- a/umap/views.py +++ b/umap/views.py @@ -13,6 +13,7 @@ from smtplib import SMTPException from urllib.error import HTTPError, URLError from urllib.parse import quote_plus, urlparse from urllib.request import Request, build_opener +from uuid import UUID from django.conf import settings from django.contrib import messages @@ -1181,8 +1182,17 @@ class DataLayerCreate(FormLessEditMixin, GZipMixin, CreateView): def form_valid(self, form): form.instance.map = self.kwargs["map_inst"] + + uuid = self.kwargs["pk"] + # Check if UUID already exists + if DataLayer.objects.filter(uuid=uuid).exists(): + return HttpResponseBadRequest("UUID already exists") + + form.instance.uuid = uuid self.object = form.save() - # Simple response with only metadata (including new id) + assert uuid == self.object.uuid + + # Simple response with only metadata response = simple_json_response(**self.object.metadata(self.request)) response["X-Datalayer-Version"] = self.version return response