mirror of
https://github.com/umap-project/umap.git
synced 2025-05-04 21:51:50 +02:00
feat(sync): Let the clients set layers UUID
This make it possible to synchronize datalayers before their creation on the server, allowing at the same time to solve issues related to them not being saved (e.g. duplication of geometries)
This commit is contained in:
parent
200e12e0d9
commit
9759f780ad
6 changed files with 41 additions and 17 deletions
|
@ -444,7 +444,7 @@ class DataLayer(NamedModel):
|
||||||
(OWNER, _("Owner only")),
|
(OWNER, _("Owner only")),
|
||||||
)
|
)
|
||||||
uuid = models.UUIDField(
|
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)
|
old_id = models.IntegerField(null=True, blank=True)
|
||||||
map = models.ForeignKey(Map, on_delete=models.CASCADE)
|
map = models.ForeignKey(Map, on_delete=models.CASCADE)
|
||||||
|
|
|
@ -139,7 +139,7 @@ class Feature {
|
||||||
subject: 'feature',
|
subject: 'feature',
|
||||||
metadata: {
|
metadata: {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
layerId: this.datalayer?.umap_id || null,
|
layerId: this.datalayer.umap_id,
|
||||||
featureType: this.getClassName(),
|
featureType: this.getClassName(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ const LAYER_MAP = LAYER_TYPES.reduce((acc, klass) => {
|
||||||
}, {})
|
}, {})
|
||||||
|
|
||||||
export class DataLayer {
|
export class DataLayer {
|
||||||
constructor(map, data) {
|
constructor(map, data, sync) {
|
||||||
this.map = map
|
this.map = map
|
||||||
this.sync = map.sync_engine.proxy(this)
|
this.sync = map.sync_engine.proxy(this)
|
||||||
this._index = Array()
|
this._index = Array()
|
||||||
|
@ -78,7 +78,9 @@ export class DataLayer {
|
||||||
this.backupOptions()
|
this.backupOptions()
|
||||||
this.connectToMap()
|
this.connectToMap()
|
||||||
this.permissions = new DataLayerPermissions(this)
|
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()
|
if (this.showAtLoad()) this.show()
|
||||||
this.isDirty = true
|
this.isDirty = true
|
||||||
}
|
}
|
||||||
|
@ -89,6 +91,11 @@ export class DataLayer {
|
||||||
if (this.isVisible()) this.propagateShow()
|
if (this.isVisible()) this.propagateShow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get createdOnServer(){
|
||||||
|
console.log("reference version", this._reference_version)
|
||||||
|
return this._reference_version !== undefined
|
||||||
|
}
|
||||||
|
|
||||||
set isDirty(status) {
|
set isDirty(status) {
|
||||||
this._isDirty = status
|
this._isDirty = status
|
||||||
if (status) {
|
if (status) {
|
||||||
|
@ -119,7 +126,7 @@ export class DataLayer {
|
||||||
return {
|
return {
|
||||||
subject: 'datalayer',
|
subject: 'datalayer',
|
||||||
metadata: {
|
metadata: {
|
||||||
id: this.umap_id || null,
|
id: this.umap_id,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,7 +219,7 @@ export class DataLayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchData() {
|
async fetchData() {
|
||||||
if (!this.umap_id) return
|
if (!this.createdOnServer) return
|
||||||
if (this._loading) return
|
if (this._loading) return
|
||||||
this._loading = true
|
this._loading = true
|
||||||
const [geojson, response, error] = await this.map.server.get(this._dataUrl())
|
const [geojson, response, error] = await this.map.server.get(this._dataUrl())
|
||||||
|
@ -304,7 +311,7 @@ export class DataLayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
isLoaded() {
|
isLoaded() {
|
||||||
return !this.umap_id || this._loaded
|
return !this.createdOnServer || this._loaded
|
||||||
}
|
}
|
||||||
|
|
||||||
hasDataLoaded() {
|
hasDataLoaded() {
|
||||||
|
@ -312,8 +319,13 @@ export class DataLayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
setUmapId(id) {
|
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
|
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() {
|
backupOptions() {
|
||||||
|
@ -571,7 +583,7 @@ export class DataLayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
if (!this.umap_id) this.erase()
|
if (!this.createdOnServer) this.erase()
|
||||||
|
|
||||||
this.resetOptions()
|
this.resetOptions()
|
||||||
this.parentPane.appendChild(this.pane)
|
this.parentPane.appendChild(this.pane)
|
||||||
|
@ -1040,14 +1052,16 @@ export class DataLayer {
|
||||||
// Filename support is shaky, don't do it for now.
|
// Filename support is shaky, don't do it for now.
|
||||||
const blob = new Blob([JSON.stringify(geojson)], { type: 'application/json' })
|
const blob = new Blob([JSON.stringify(geojson)], { type: 'application/json' })
|
||||||
formData.append('geojson', blob)
|
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,
|
map_id: this.map.options.umap_id,
|
||||||
pk: this.umap_id,
|
pk: this.umap_id,
|
||||||
|
created: this.createdOnServer,
|
||||||
})
|
})
|
||||||
|
console.log("saveUrl", saveURL)
|
||||||
const headers = this._reference_version
|
const headers = this._reference_version
|
||||||
? { 'X-Datalayer-Reference': this._reference_version }
|
? { 'X-Datalayer-Reference': this._reference_version }
|
||||||
: {}
|
: {}
|
||||||
await this._trySave(saveUrl, headers, formData)
|
await this._trySave(saveURL, headers, formData)
|
||||||
this._geojson = geojson
|
this._geojson = geojson
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1076,7 +1090,7 @@ export class DataLayer {
|
||||||
this._reference_version = response.headers.get('X-Datalayer-Version')
|
this._reference_version = response.headers.get('X-Datalayer-Version')
|
||||||
this.sync.update('_reference_version', this._reference_version)
|
this.sync.update('_reference_version', this._reference_version)
|
||||||
|
|
||||||
this.setUmapId(data.id)
|
// this.setUmapId(data.id)
|
||||||
this.updateOptions(data)
|
this.updateOptions(data)
|
||||||
this.backupOptions()
|
this.backupOptions()
|
||||||
this.connectToMap()
|
this.connectToMap()
|
||||||
|
|
|
@ -25,8 +25,8 @@ export default class URLs {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the layer if pk is passed, create otherwise.
|
// Update the layer if pk is passed, create otherwise.
|
||||||
datalayer_save({ map_id, pk }, ...options) {
|
datalayer_save({ map_id, pk, created}, ...options) {
|
||||||
if (pk) return this.get('datalayer_update', { map_id, pk }, ...options)
|
if (created) return this.get('datalayer_update', { map_id, pk }, ...options)
|
||||||
return this.get('datalayer_create', { map_id, pk }, ...options)
|
return this.get('datalayer_create', { map_id, pk }, ...options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,8 +155,8 @@ map_urls = [
|
||||||
views.MapClone.as_view(),
|
views.MapClone.as_view(),
|
||||||
name="map_clone",
|
name="map_clone",
|
||||||
),
|
),
|
||||||
re_path(
|
path(
|
||||||
r"^map/(?P<map_id>[\d]+)/datalayer/create/$",
|
"map/<int:map_id>/datalayer/create/<uuid:pk>/",
|
||||||
views.DataLayerCreate.as_view(),
|
views.DataLayerCreate.as_view(),
|
||||||
name="datalayer_create",
|
name="datalayer_create",
|
||||||
),
|
),
|
||||||
|
|
|
@ -13,6 +13,7 @@ from smtplib import SMTPException
|
||||||
from urllib.error import HTTPError, URLError
|
from urllib.error import HTTPError, URLError
|
||||||
from urllib.parse import quote_plus, urlparse
|
from urllib.parse import quote_plus, urlparse
|
||||||
from urllib.request import Request, build_opener
|
from urllib.request import Request, build_opener
|
||||||
|
from uuid import UUID
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
@ -1181,8 +1182,17 @@ class DataLayerCreate(FormLessEditMixin, GZipMixin, CreateView):
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
form.instance.map = self.kwargs["map_inst"]
|
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()
|
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 = simple_json_response(**self.object.metadata(self.request))
|
||||||
response["X-Datalayer-Version"] = self.version
|
response["X-Datalayer-Version"] = self.version
|
||||||
return response
|
return response
|
||||||
|
|
Loading…
Reference in a new issue